diff --git a/.gitignore b/.gitignore index 71cf88f79e6..8bc6ef23fbb 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,4 @@ tests/cargo-fmt/**/target # Editors' specific files .idea/ -.vscode/ *~ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..910809344b6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.rustc.source": "discover" +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e3fc87feca4..2d476a619ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -56,7 +56,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -87,6 +87,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + [[package]] name = "bstr" version = "0.2.17" @@ -131,7 +137,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.40", ] [[package]] @@ -214,9 +220,9 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] @@ -233,14 +239,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users", - "windows-sys", + "redox_users 0.5.2", + "windows-sys 0.61.0", ] [[package]] @@ -250,7 +256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.3", "winapi", ] @@ -366,6 +372,16 @@ version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +[[package]] +name = "libredox" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +dependencies = [ + "bitflags 2.9.4", + "libc", +] + [[package]] name = "log" version = "0.4.16" @@ -426,9 +442,9 @@ checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -448,7 +464,7 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -459,7 +475,18 @@ checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", "redox_syscall", - "thiserror", + "thiserror 1.0.40", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom", + "libredox", + "thiserror 2.0.16", ] [[package]] @@ -518,7 +545,7 @@ dependencies = [ "serde", "serde_json", "term", - "thiserror", + "thiserror 1.0.40", "toml", "tracing", "tracing-subscriber", @@ -620,9 +647,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -646,7 +673,16 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.40", +] + +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl 2.0.16", ] [[package]] @@ -660,6 +696,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -837,6 +884,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-sys" version = "0.48.0" @@ -846,6 +899,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 07bc74a5127..1b5f0b1244c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ cargo_metadata = "0.18" clap = { version = "4.4.2", features = ["derive"] } clap-cargo = "0.12.0" diff = "0.1" -dirs = "5.0" +dirs = "6.0" getopts = "0.2" ignore = "0.4" itertools = "0.12" diff --git a/rust-toolchain b/rust-toolchain index 80851788276..0a1f77b2ad5 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-04-02" +channel = "nightly-2025-09-08" components = ["llvm-tools", "rustc-dev"] diff --git a/src/attr.rs b/src/attr.rs index e2104617fdc..405d30233be 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -243,10 +243,6 @@ fn rewrite_initial_doc_comments( } impl Rewrite for ast::MetaItemInner { - 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 { ast::MetaItemInner::MetaItem(ref meta_item) => meta_item.rewrite_result(context, shape), @@ -277,10 +273,6 @@ fn has_newlines_before_after_comment(comment: &str) -> (&str, &str) { } impl Rewrite for ast::MetaItem { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { Ok(match self.kind { ast::MetaItemKind::Word => { @@ -323,10 +315,6 @@ impl Rewrite for ast::MetaItem { } impl Rewrite for ast::Attribute { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { let snippet = context.snippet(self.span); if self.is_doc_comment() { @@ -385,10 +373,6 @@ impl Rewrite for ast::Attribute { } impl Rewrite for [ast::Attribute] { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { if self.is_empty() { return Ok(String::new()); diff --git a/src/chains.rs b/src/chains.rs index 9ab20b355fb..e0659772022 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -58,7 +58,7 @@ use std::borrow::Cow; use std::cmp::min; -use rustc_ast::{ast, ptr}; +use rustc_ast::ast; use rustc_span::{BytePos, Span, symbol}; use tracing::debug; @@ -190,7 +190,7 @@ enum ChainItemKind { MethodCall( ast::PathSegment, Vec, - ThinVec>, + ThinVec>, ), StructField(symbol::Ident), TupleField(symbol::Ident, bool), @@ -290,10 +290,6 @@ impl ChainItemKind { } impl Rewrite for ChainItem { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { let shape = shape.sub_width(self.tries, self.span)?; let rewrite = match self.kind { @@ -351,7 +347,7 @@ impl ChainItem { fn rewrite_method_call( method_name: symbol::Ident, types: &[ast::GenericArg], - args: &[ptr::P], + args: &[Box], span: Span, context: &RewriteContext<'_>, shape: Shape, @@ -548,10 +544,6 @@ impl Chain { } impl Rewrite for Chain { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { debug!("rewrite chain {:?} {:?}", self, shape); @@ -567,6 +559,7 @@ impl Rewrite for Chain { formatter.format_root(&self.parent, context, shape)?; if let Some(result) = formatter.pure_root() { return wrap_str(result, context.config.max_width(), shape) + .ok() .max_width_error(shape.width, self.parent.span); } @@ -582,7 +575,9 @@ impl Rewrite for Chain { formatter.format_last_child(context, shape, child_shape)?; let result = formatter.join_rewrites(context, child_shape)?; - wrap_str(result, context.config.max_width(), shape).max_width_error(shape.width, full_span) + wrap_str(result, context.config.max_width(), shape) + .ok() + .max_width_error(shape.width, full_span) } } diff --git a/src/closures.rs b/src/closures.rs index ca733e7aaaf..dc86514b553 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -1,4 +1,7 @@ -use rustc_ast::{Label, ast, ptr}; +use std::backtrace::Backtrace; +use std::sync::Arc; + +use rustc_ast::{Label, ast}; use rustc_span::Span; use thin_vec::thin_vec; use tracing::debug; @@ -10,7 +13,7 @@ use crate::expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewr use crate::items::{span_hi_for_param, span_lo_for_param}; use crate::lists::{ListFormatting, Separator, definitive_tactic, itemize_list, write_list}; use crate::overflow::OverflowableItem; -use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult}; +use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteResult}; use crate::shape::Shape; use crate::source_map::SpanUtils; use crate::types::rewrite_bound_params; @@ -67,7 +70,7 @@ pub(crate) fn rewrite_closure( ast::FnRetTy::Default(_) if !context.inside_macro() => { try_rewrite_without_block(body, &prefix, context, shape, body_shape) } - _ => Err(RewriteError::Unknown), + _ => Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), }; result.or_else(|_| { @@ -163,13 +166,13 @@ fn rewrite_closure_with_block( let left_most = left_most_sub_expr(body); let veto_block = veto_block(body) && !expr_requires_semi_to_be_stmt(left_most); if veto_block { - return Err(RewriteError::Unknown); + return Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))); } let block = ast::Block { stmts: thin_vec![ast::Stmt { id: ast::NodeId::root(), - kind: ast::StmtKind::Expr(ptr::P(body.clone())), + kind: ast::StmtKind::Expr(Box::new(body.clone())), span: body.span, }], id: ast::NodeId::root(), @@ -225,7 +228,7 @@ fn rewrite_closure_expr( expr.rewrite_result(context, shape) .and_then(|rw| { if veto_multiline && rw.contains('\n') { - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } else { Ok(rw) } @@ -270,8 +273,7 @@ fn rewrite_closure_fn_decl( "for<> ".to_owned() } ast::ClosureBinder::For { generic_params, .. } => { - let lifetime_str = - rewrite_bound_params(context, shape, generic_params).unknown_error()?; + let lifetime_str = rewrite_bound_params(context, shape, generic_params)?; format!("for<{lifetime_str}> ") } ast::ClosureBinder::NotPresent => "".to_owned(), @@ -402,7 +404,7 @@ pub(crate) fn rewrite_last_closure( )?; // If the closure goes multi line before its body, do not overflow the closure. if prefix.contains('\n') { - return Err(RewriteError::Unknown); + return Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))); } let body_shape = shape.offset_left(extra_offset, expr.span)?; @@ -443,7 +445,7 @@ pub(crate) fn rewrite_last_closure( // Seems fine, just format the closure in usual manner. return expr.rewrite_result(context, shape); } - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } /// Returns `true` if the given vector of arguments has more than one `ast::ExprKind::Closure`. diff --git a/src/comment.rs b/src/comment.rs index 709031dda44..a224c502c1d 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -687,11 +687,11 @@ impl<'a> CommentRewrite<'a> { &item_fmt, self.max_width.saturating_sub(ib.indent), ) { - Some(s) => self.result.push_str(&Self::join_block( + Ok(s) => self.result.push_str(&Self::join_block( &s, &format!("{}{}", self.comment_line_separator, ib.line_start), )), - None => self.result.push_str(&Self::join_block( + Err(_) => self.result.push_str(&Self::join_block( &ib.original_block_as_string(), &self.comment_line_separator, )), @@ -742,11 +742,11 @@ impl<'a> CommentRewrite<'a> { &item_fmt, self.max_width.saturating_sub(ib.indent), ) { - Some(s) => self.result.push_str(&Self::join_block( + Ok(s) => self.result.push_str(&Self::join_block( &s, &format!("{}{}", self.comment_line_separator, ib.line_start), )), - None => self.result.push_str(&Self::join_block( + Err(_) => self.result.push_str(&Self::join_block( &ib.original_block_as_string(), &self.comment_line_separator, )), @@ -842,28 +842,28 @@ impl<'a> CommentRewrite<'a> { if should_wrap_comment { match rewrite_string(line, &self.fmt, self.max_width) { - Some(ref s) => { + Ok(ref s) => { self.is_prev_line_multi_line = s.contains('\n'); self.result.push_str(s); } - None if self.is_prev_line_multi_line => { + Err(_) if self.is_prev_line_multi_line => { // We failed to put the current `line` next to the previous `line`. // Remove the trailing space, then start rewrite on the next line. self.result.pop(); self.result.push_str(&self.comment_line_separator); self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent); match rewrite_string(line, &self.fmt, self.max_width) { - Some(ref s) => { + Ok(ref s) => { self.is_prev_line_multi_line = s.contains('\n'); self.result.push_str(s); } - None => { + Err(_) => { self.is_prev_line_multi_line = false; self.result.push_str(line); } } } - None => { + Err(_) => { self.is_prev_line_multi_line = false; self.result.push_str(line); } diff --git a/src/expr.rs b/src/expr.rs index 348cffc21ee..68f54c7003c 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1,9 +1,11 @@ +use std::backtrace::Backtrace; use std::borrow::Cow; use std::cmp::min; +use std::sync::Arc; use itertools::Itertools; use rustc_ast::token::{Delimiter, Lit, LitKind}; -use rustc_ast::{ForLoopKind, MatchKind, ast, ptr, token}; +use rustc_ast::{ForLoopKind, MatchKind, ast, token}; use rustc_span::{BytePos, Span}; use tracing::debug; @@ -39,10 +41,6 @@ use crate::vertical::rewrite_with_alignment; use crate::visitor::FmtVisitor; impl Rewrite for ast::Expr { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { format_expr(self, ExprType::SubExpression, context, shape) } @@ -116,7 +114,7 @@ pub(crate) fn format_expr( if let LitKind::StrRaw(_) = token_lit.kind { Ok(context.snippet(expr.span).trim().into()) } else { - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } } } @@ -166,7 +164,6 @@ pub(crate) fn format_expr( | ast::ExprKind::ForLoop { .. } | ast::ExprKind::Loop(..) | ast::ExprKind::While(..) => to_control_flow(expr, expr_type) - .unknown_error() .and_then(|control_flow| control_flow.rewrite_result(context, shape)), ast::ExprKind::ConstBlock(ref anon_const) => { let rewrite = match anon_const.value.kind { @@ -281,6 +278,7 @@ pub(crate) fn format_expr( context.config.max_width(), shape, ) + .ok() .max_width_error(shape.width, expr.span) }) } @@ -453,9 +451,11 @@ pub(crate) fn format_expr( // rustfmt tries to parse macro arguments when formatting macros, so it's not totally // impossible for rustfmt to come across one of these nodes when formatting a file. // Also, rustfmt might get passed the output from `-Zunpretty=expanded`. - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) + } + ast::ExprKind::Err(_) | ast::ExprKind::Dummy => { + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } - ast::ExprKind::Err(_) | ast::ExprKind::Dummy => Err(RewriteError::Unknown), }; expr_rw @@ -577,7 +577,7 @@ fn rewrite_single_line_block( return Ok(result); } } - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } pub(crate) fn rewrite_block_with_visitor( @@ -617,10 +617,6 @@ pub(crate) fn rewrite_block_with_visitor( } impl Rewrite for ast::Block { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { rewrite_block(self, None, None, context, shape) } @@ -678,22 +674,24 @@ pub(crate) fn rewrite_cond( context: &RewriteContext<'_>, expr: &ast::Expr, shape: Shape, -) -> Option { +) -> RewriteResult { match expr.kind { ast::ExprKind::Match(ref cond, _, MatchKind::Prefix) => { // `match `cond` {` let cond_shape = match context.config.indent_style() { - IndentStyle::Visual => shape.shrink_left_opt(6).and_then(|s| s.sub_width_opt(2))?, - IndentStyle::Block => shape.offset_left_opt(8)?, + IndentStyle::Visual => shape + .shrink_left_opt(6) + .and_then(|s| s.sub_width_opt(2)) + .unknown_error()?, + IndentStyle::Block => shape.offset_left_opt(8).unknown_error()?, }; - cond.rewrite(context, cond_shape) + cond.rewrite_result(context, cond_shape) } _ => to_control_flow(expr, ExprType::SubExpression).and_then(|control_flow| { let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config); control_flow .rewrite_cond(context, shape, &alt_block_sep) - .ok() .map(|rw| rw.0) }), } @@ -724,11 +722,11 @@ fn extract_pats_and_cond(expr: &ast::Expr) -> (Option<&ast::Pat>, &ast::Expr) { } // FIXME: Refactor this. -fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option> { +fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Result, RewriteError> { match expr.kind { ast::ExprKind::If(ref cond, ref if_block, ref else_block) => { let (pat, cond) = extract_pats_and_cond(cond); - Some(ControlFlow::new_if( + Ok(ControlFlow::new_if( cond, pat, if_block, @@ -744,17 +742,17 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option Some(ControlFlow::new_for( + } => Ok(ControlFlow::new_for( pat, iter, body, label, expr.span, kind, )), ast::ExprKind::Loop(ref block, label, _) => { - Some(ControlFlow::new_loop(block, label, expr.span)) + Ok(ControlFlow::new_loop(block, label, expr.span)) } ast::ExprKind::While(ref cond, ref block, label) => { let (pat, cond) = extract_pats_and_cond(cond); - Some(ControlFlow::new_while(pat, cond, block, label, expr.span)) + Ok(ControlFlow::new_while(pat, cond, block, label, expr.span)) } - _ => None, + _ => None.unknown_error(), } } @@ -858,9 +856,9 @@ impl<'a> ControlFlow<'a> { pat_expr_str: &str, context: &RewriteContext<'_>, width: usize, - ) -> Option { + ) -> RewriteResult { assert!(self.allow_single_line); - let else_block = self.else_block?; + let else_block = self.else_block.unknown_error()?; let fixed_cost = self.keyword.len() + " { } else { }".len(); if let ast::ExprKind::Block(ref else_node, _) = else_block.kind { @@ -870,17 +868,21 @@ impl<'a> ControlFlow<'a> { pat_expr_str.contains('\n'), ) { (Some(if_expr), Some(else_expr), false) => (if_expr, else_expr), - _ => return None, + _ => return None.unknown_error(), }; - let new_width = width.checked_sub(pat_expr_str.len() + fixed_cost)?; - let if_str = if_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?; + let new_width = width + .checked_sub(pat_expr_str.len() + fixed_cost) + .unknown_error()?; + let if_str = + if_expr.rewrite_result(context, Shape::legacy(new_width, Indent::empty()))?; - let new_width = new_width.checked_sub(if_str.len())?; - let else_str = else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?; + let new_width = new_width.checked_sub(if_str.len()).unknown_error()?; + let else_str = + else_expr.rewrite_result(context, Shape::legacy(new_width, Indent::empty()))?; if if_str.contains('\n') || else_str.contains('\n') { - return None; + return None.unknown_error(); } let result = format!( @@ -889,11 +891,11 @@ impl<'a> ControlFlow<'a> { ); if result.len() <= width { - return Some(result); + return Ok(result); } } - None + None.unknown_error() } } @@ -1014,7 +1016,7 @@ impl<'a> ControlFlow<'a> { if self.allow_single_line && context.config.single_line_if_else_max_width() > 0 { let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width); - if let Some(cond_str) = trial { + if let Ok(cond_str) = trial { if cond_str.len() <= context.config.single_line_if_else_max_width() { return Ok((cond_str, 0)); } @@ -1134,10 +1136,6 @@ pub(crate) fn rewrite_else_kw_with_comments( } impl<'a> Rewrite for ControlFlow<'a> { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { debug!("ControlFlow::rewrite {:?} {:?}", self, shape); @@ -1308,6 +1306,7 @@ pub(crate) fn rewrite_literal( context.config.max_width(), shape, ) + .ok() .max_width_error(shape.width, span), } } @@ -1325,6 +1324,7 @@ fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) -> return Ok(string_lit.to_owned()); } else { return wrap_str(string_lit.to_owned(), context.config.max_width(), shape) + .ok() .max_width_error(shape.width, span); } } @@ -1337,6 +1337,7 @@ fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) -> &StringFormat::new(shape.visual_indent(0), context.config), shape.width.saturating_sub(2), ) + .ok() .max_width_error(shape.width, span) } @@ -1368,6 +1369,7 @@ fn rewrite_int_lit( context.config.max_width(), shape, ) + .ok() .max_width_error(shape.width, span); } } @@ -1377,6 +1379,7 @@ fn rewrite_int_lit( context.config.max_width(), shape, ) + .ok() .max_width_error(shape.width, span) } @@ -1395,6 +1398,7 @@ fn rewrite_float_lit( context.config.max_width(), shape, ) + .ok() .max_width_error(shape.width, span); } @@ -1443,6 +1447,7 @@ fn rewrite_float_lit( context.config.max_width(), shape, ) + .ok() .max_width_error(shape.width, span) } @@ -1461,7 +1466,7 @@ fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option, callee: &str, - args: &[ptr::P], + args: &[Box], span: Span, shape: Shape, ) -> RewriteResult { @@ -1724,7 +1729,7 @@ fn struct_lit_can_be_aligned(fields: &[ast::ExprField], has_base: bool) -> bool fn rewrite_struct_lit<'a>( context: &RewriteContext<'_>, path: &ast::Path, - qself: &Option>, + qself: &Option>, fields: &'a [ast::ExprField], struct_rest: &ast::StructRest, attrs: &[ast::Attribute], @@ -1766,8 +1771,7 @@ fn rewrite_struct_lit<'a>( v_shape, mk_sp(body_lo, span.hi()), one_line_width, - ) - .unknown_error()? + )? } else { let field_iter = fields.iter().map(StructLitField::Regular).chain( match struct_rest { @@ -2127,7 +2131,7 @@ fn rewrite_assignment( context: &RewriteContext<'_>, lhs: &ast::Expr, rhs: &ast::Expr, - op: Option<&ast::BinOp>, + op: Option<&ast::AssignOp>, shape: Shape, ) -> RewriteResult { let operator_str = match op { @@ -2357,8 +2361,10 @@ fn rewrite_expr_addrof( ) -> RewriteResult { let operator_str = match (mutability, borrow_kind) { (ast::Mutability::Not, ast::BorrowKind::Ref) => "&", + (ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ", (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ", (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ", + (ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ", (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ", }; rewrite_unary_prefix(context, operator_str, expr, shape) diff --git a/src/imports.rs b/src/imports.rs index 2e42861d1dc..e8cb2dcc214 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -184,7 +184,7 @@ impl UseSegment { modsep: bool, ) -> Option { let name = rewrite_ident(context, path_seg.ident); - if name.is_empty() || name == "{{root}}" { + if name.is_empty() { return None; } let kind = match name { @@ -1092,10 +1092,6 @@ fn rewrite_nested_use_tree( } impl Rewrite for UseSegment { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { Ok(match self.kind { UseSegmentKind::Ident(ref ident, Some(ref rename)) => { @@ -1125,10 +1121,6 @@ impl Rewrite for UseSegment { } impl Rewrite for UseTree { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - // This does NOT format attributes and visibility or add a trailing `;`. fn rewrite_result(&self, context: &RewriteContext<'_>, mut shape: Shape) -> RewriteResult { let mut result = String::with_capacity(256); diff --git a/src/items.rs b/src/items.rs index 0e814644304..32e929017ca 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1,11 +1,13 @@ // Formatting top-level items - functions, structs, enums, traits, impls. +use std::backtrace::Backtrace; use std::borrow::Cow; use std::cmp::{Ordering, max, min}; +use std::sync::Arc; use regex::Regex; +use rustc_ast::ast; use rustc_ast::visit; -use rustc_ast::{ast, ptr}; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, symbol}; use tracing::debug; @@ -49,10 +51,6 @@ fn type_annotation_separator(config: &Config) -> &str { // Statements of the form // let pat: ty = init; or let pat: ty = init else { .. }; impl Rewrite for ast::Local { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { debug!( "Local::rewrite {:?} {} {:?}", @@ -65,6 +63,11 @@ impl Rewrite for ast::Local { return Err(RewriteError::SkipFormatting); } + // FIXME(super_let): Implement formatting + if self.super_.is_some() { + return Err(RewriteError::SkipFormatting); + } + let attrs_str = self.attrs.rewrite_result(context, shape)?; let mut result = if attrs_str.is_empty() { "let ".to_owned() @@ -406,7 +409,7 @@ impl<'a> FmtVisitor<'a> { } fn format_foreign_item(&mut self, item: &ast::ForeignItem) { - let rewrite = item.rewrite(&self.get_context(), self.shape()); + let rewrite = item.rewrite_result(&self.get_context(), self.shape()); let hi = item.span.hi(); let span = if item.attrs.is_empty() { item.span @@ -479,9 +482,9 @@ impl<'a> FmtVisitor<'a> { fn_str: &str, block: &ast::Block, inner_attrs: Option<&[ast::Attribute]>, - ) -> Option { + ) -> Result { if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) { - return None; + return None.unknown_error(); } let context = self.get_context(); @@ -491,21 +494,21 @@ impl<'a> FmtVisitor<'a> { && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width() && !last_line_contains_single_line_comment(fn_str) { - return Some(format!("{fn_str} {{}}")); + return Ok(format!("{fn_str} {{}}")); } if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) { - return None; + return None.unknown_error(); } - let res = Stmt::from_ast_node(block.stmts.first()?, true) - .rewrite(&self.get_context(), self.shape())?; + let res = Stmt::from_ast_node(block.stmts.first().unknown_error()?, true) + .rewrite_result(&self.get_context(), self.shape())?; let width = self.block_indent.width() + fn_str.len() + res.len() + 5; if !res.contains('\n') && width <= self.config.max_width() { - Some(format!("{fn_str} {{ {res} }}")) + Ok(format!("{fn_str} {{ {res} }}")) } else { - None + None.unknown_error() } } @@ -559,7 +562,7 @@ impl<'a> FmtVisitor<'a> { self.last_pos = body_start; match self.format_variant_list(enum_def, body_start, span.hi()) { - Some(ref s) if enum_def.variants.is_empty() => self.push_str(s), + Ok(ref s) if enum_def.variants.is_empty() => self.push_str(s), rw => { self.push_rewrite(mk_sp(body_start, span.hi()), rw); self.block_indent = self.block_indent.block_unindent(self.config); @@ -573,7 +576,7 @@ impl<'a> FmtVisitor<'a> { enum_def: &ast::EnumDef, body_lo: BytePos, body_hi: BytePos, - ) -> Option { + ) -> Result { if enum_def.variants.is_empty() { let mut buffer = String::with_capacity(128); // 1 = "}" @@ -586,7 +589,7 @@ impl<'a> FmtVisitor<'a> { "", "}", ); - return Some(buffer); + return Ok(buffer); } let mut result = String::with_capacity(1024); let original_offset = self.block_indent; @@ -623,10 +626,7 @@ impl<'a> FmtVisitor<'a> { } }, |f| f.span.hi(), - |f| { - self.format_variant(f, one_line_width, pad_discrim_ident_to) - .unknown_error() - }, + |f| self.format_variant(f, one_line_width, pad_discrim_ident_to), body_lo, body_hi, false, @@ -642,16 +642,16 @@ impl<'a> FmtVisitor<'a> { items = itemize_list_with(0); } - let shape = self.shape().sub_width_opt(2)?; + let shape = self.shape().sub_width_opt(2).unknown_error()?; let fmt = ListFormatting::new(shape, self.config) .trailing_separator(self.config.trailing_comma()) .preserve_newline(true); - let list = write_list(&items, &fmt).ok()?; + let list = write_list(&items, &fmt)?; result.push_str(&list); result.push_str(&original_offset.to_string_with_newline(self.config)); result.push('}'); - Some(result) + Ok(result) } // Variant of an enum. @@ -660,23 +660,25 @@ impl<'a> FmtVisitor<'a> { field: &ast::Variant, one_line_width: usize, pad_discrim_ident_to: usize, - ) -> Option { + ) -> Result { if contains_skip(&field.attrs) { let lo = field.attrs[0].span.lo(); let span = mk_sp(lo, field.span.hi()); - return Some(self.snippet(span).to_owned()); + return Ok(self.snippet(span).to_owned()); } let context = self.get_context(); let shape = self.shape(); let attrs_str = if context.config.style_edition() >= StyleEdition::Edition2024 { - field.attrs.rewrite(&context, shape)? + field.attrs.rewrite_result(&context, shape)? } else { // StyleEdition::Edition20{15|18|21} formatting that was off by 1. See issue #5801 - field.attrs.rewrite(&context, shape.sub_width_opt(1)?)? + field + .attrs + .rewrite_result(&context, shape.sub_width_opt(1).unknown_error()?)? }; // sub_width(1) to take the trailing comma into account - let shape = shape.sub_width_opt(1)?; + let shape = shape.sub_width_opt(1).unknown_error()?; let lo = field .attrs @@ -704,19 +706,17 @@ impl<'a> FmtVisitor<'a> { shape, &RhsAssignKind::Expr(&ex.kind, ex.span), RhsTactics::AllowOverflow, - ) - .ok()? + )? } else { variant_body }; combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false) - .ok() } - fn visit_impl_items(&mut self, items: &[ptr::P]) { + fn visit_impl_items(&mut self, items: &[Box]) { if self.get_context().config.reorder_impl_items() { - type TyOpt = Option>; + type TyOpt = Option>; use crate::ast::AssocItemKind::*; let is_type = |ty: &TyOpt| opaque_ty(ty).is_none(); let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some(); @@ -922,7 +922,7 @@ pub(crate) fn format_impl( fn is_impl_single_line( context: &RewriteContext<'_>, - items: &[ptr::P], + items: &[Box], result: &str, where_clause_str: &str, item: &ast::Item, @@ -944,20 +944,19 @@ fn format_impl_ref_and_type( offset: Indent, ) -> RewriteResult { let ast::Impl { - safety, - polarity, - defaultness, - constness, - ref generics, - of_trait: ref trait_ref, - ref self_ty, - .. - } = *iimpl; + generics, + of_trait, + self_ty, + items: _, + } = iimpl; let mut result = String::with_capacity(128); result.push_str(&format_visibility(context, &item.vis)); - result.push_str(format_defaultness(defaultness)); - result.push_str(format_safety(safety)); + + if let Some(of_trait) = of_trait.as_deref() { + result.push_str(format_defaultness(of_trait.defaultness)); + result.push_str(format_safety(of_trait.safety)); + } let shape = if context.config.style_edition() >= StyleEdition::Edition2024 { Shape::indented(offset + last_line_width(&result), context.config) @@ -971,28 +970,24 @@ fn format_impl_ref_and_type( }; let generics_str = rewrite_generics(context, "impl", generics, shape)?; result.push_str(&generics_str); - result.push_str(format_constness_right(constness)); - let polarity_str = match polarity { - ast::ImplPolarity::Negative(_) => "!", - ast::ImplPolarity::Positive => "", - }; - - let polarity_overhead; let trait_ref_overhead; - if let Some(ref trait_ref) = *trait_ref { + if let Some(of_trait) = of_trait.as_deref() { + result.push_str(format_constness_right(of_trait.constness)); + let polarity_str = match of_trait.polarity { + ast::ImplPolarity::Negative(_) => "!", + ast::ImplPolarity::Positive => "", + }; let result_len = last_line_width(&result); result.push_str(&rewrite_trait_ref( context, - trait_ref, + &of_trait.trait_ref, offset, polarity_str, result_len, )?); - polarity_overhead = 0; // already written trait_ref_overhead = " for".len(); } else { - polarity_overhead = polarity_str.len(); trait_ref_overhead = 0; } @@ -1007,17 +1002,15 @@ fn format_impl_ref_and_type( } else { 0 }; - let used_space = - last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead; + let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead; // 1 = space before the type. let budget = context.budget(used_space + 1); - if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) { + if let Ok(self_ty_str) = self_ty.rewrite_result(context, Shape::legacy(budget, offset)) { if !self_ty_str.contains('\n') { - if trait_ref.is_some() { + if of_trait.is_some() { result.push_str(" for "); } else { result.push(' '); - result.push_str(polarity_str); } result.push_str(&self_ty_str); return Ok(result); @@ -1029,12 +1022,10 @@ fn format_impl_ref_and_type( // Add indentation of one additional tab. let new_line_offset = offset.block_indent(context.config); result.push_str(&new_line_offset.to_string(context.config)); - if trait_ref.is_some() { + if of_trait.is_some() { result.push_str("for "); - } else { - result.push_str(polarity_str); } - let budget = context.budget(last_line_width(&result) + polarity_overhead); + let budget = context.budget(last_line_width(&result)); let type_offset = match context.config.indent_style() { IndentStyle::Visual => new_line_offset + trait_ref_overhead, IndentStyle::Block => new_line_offset, @@ -1097,10 +1088,10 @@ impl<'a> StructParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { let (prefix, def, ident, generics) = match item.kind { - ast::ItemKind::Struct(ident, ref def, ref generics) => { + ast::ItemKind::Struct(ident, ref generics, ref def) => { ("struct ", def, ident, generics) } - ast::ItemKind::Union(ident, ref def, ref generics) => ("union ", def, ident, generics), + ast::ItemKind::Union(ident, ref generics, ref def) => ("union ", def, ident, generics), _ => unreachable!(), }; StructParts { @@ -1138,7 +1129,7 @@ fn format_struct( struct_parts: &StructParts<'_>, offset: Indent, one_line_width: Option, -) -> Option { +) -> Result { match struct_parts.def { ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset), ast::VariantData::Tuple(fields, _) => { @@ -1157,6 +1148,7 @@ pub(crate) fn format_trait( offset: Indent, ) -> RewriteResult { let ast::Trait { + constness, is_auto, safety, ident, @@ -1167,8 +1159,9 @@ pub(crate) fn format_trait( let mut result = String::with_capacity(128); let header = format!( - "{}{}{}trait ", + "{}{}{}{}trait ", format_visibility(context, &item.vis), + format_constness(constness), format_safety(safety), format_auto(is_auto), ); @@ -1188,7 +1181,7 @@ pub(crate) fn format_trait( let bound_hi = bounds.last().unwrap().span().hi(); let snippet = context.snippet(mk_sp(ident_hi, bound_hi)); if contains_comment(snippet) { - return Err(RewriteError::Unknown); + return Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))); } result = rewrite_assign_rhs_with( @@ -1328,10 +1321,6 @@ pub(crate) struct TraitAliasBounds<'a> { } impl<'a> Rewrite for TraitAliasBounds<'a> { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { let generic_bounds_str = self.generic_bounds.rewrite_result(context, shape)?; @@ -1400,7 +1389,7 @@ fn format_unit_struct( context: &RewriteContext<'_>, p: &StructParts<'_>, offset: Indent, -) -> Option { +) -> Result { let header_str = format_header(context, p.prefix, p.ident, p.vis, offset); let generics_str = if let Some(generics) = p.generics { let hi = context.snippet_provider.span_before_last(p.span, ";"); @@ -1417,7 +1406,7 @@ fn format_unit_struct( } else { String::new() }; - Some(format!("{header_str}{generics_str};")) + Ok(format!("{header_str}{generics_str};")) } pub(crate) fn format_struct_struct( @@ -1426,7 +1415,7 @@ pub(crate) fn format_struct_struct( fields: &[ast::FieldDef], offset: Indent, one_line_width: Option, -) -> Option { +) -> Result { let mut result = String::with_capacity(1024); let span = struct_parts.span; @@ -1486,7 +1475,7 @@ pub(crate) fn format_struct_struct( if fields.is_empty() { let inner_span = mk_sp(body_lo, span.hi() - BytePos(1)); format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}"); - return Some(result); + return Ok(result); } // 3 = ` ` and ` }` @@ -1497,7 +1486,9 @@ pub(crate) fn format_struct_struct( let items_str = rewrite_with_alignment( fields, context, - Shape::indented(offset.block_indent(context.config), context.config).sub_width_opt(1)?, + Shape::indented(offset.block_indent(context.config), context.config) + .sub_width_opt(1) + .unknown_error()?, mk_sp(body_lo, span.hi()), one_line_budget, )?; @@ -1507,9 +1498,9 @@ pub(crate) fn format_struct_struct( && items_str.len() <= one_line_budget && !last_line_contains_single_line_comment(&items_str) { - Some(format!("{result} {items_str} }}")) + Ok(format!("{result} {items_str} }}")) } else { - Some(format!( + Ok(format!( "{}\n{}{}\n{}}}", result, offset @@ -1572,7 +1563,7 @@ fn format_tuple_struct( struct_parts: &StructParts<'_>, fields: &[ast::FieldDef], offset: Indent, -) -> Option { +) -> Result { let mut result = String::with_capacity(1024); let span = struct_parts.span; @@ -1604,7 +1595,7 @@ fn format_tuple_struct( Some(generics) => { let budget = context.budget(last_line_width(&header_str)); let shape = Shape::legacy(budget, offset); - let generics_str = rewrite_generics(context, "", generics, shape).ok()?; + let generics_str = rewrite_generics(context, "", generics, shape)?; result.push_str(&generics_str); let where_budget = context.budget(last_line_width(&result)); @@ -1620,8 +1611,7 @@ fn format_tuple_struct( None, body_hi, option, - ) - .ok()? + )? } None => "".to_owned(), }; @@ -1638,7 +1628,9 @@ fn format_tuple_struct( } else { struct_parts.ident.span.hi() }; - let shape = Shape::indented(offset, context.config).sub_width_opt(1)?; + let shape = Shape::indented(offset, context.config) + .sub_width_opt(1) + .unknown_error()?; result = overflow::rewrite_with_parens( context, &result, @@ -1647,8 +1639,7 @@ fn format_tuple_struct( mk_sp(lo, span.hi()), context.config.fn_call_width(), None, - ) - .ok()?; + )?; } if !where_clause_str.is_empty() @@ -1666,7 +1657,7 @@ fn format_tuple_struct( } result.push_str(&where_clause_str); - Some(result) + Ok(result) } #[derive(Clone, Copy)] @@ -1910,10 +1901,6 @@ pub(crate) fn rewrite_struct_field_prefix( } impl Rewrite for ast::FieldDef { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { rewrite_struct_field(context, self, shape, 0) } @@ -1927,7 +1914,7 @@ pub(crate) fn rewrite_struct_field( ) -> RewriteResult { // FIXME(default_field_values): Implement formatting. if field.default.is_some() { - return Err(RewriteError::Unknown); + return Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))); } if contains_skip(&field.attrs) { @@ -1998,7 +1985,7 @@ pub(crate) struct StaticParts<'a> { generics: Option<&'a ast::Generics>, ty: &'a ast::Ty, mutability: ast::Mutability, - expr_opt: Option<&'a ptr::P>, + expr_opt: Option<&'a Box>, defaultness: Option, span: Span, } @@ -2086,13 +2073,13 @@ fn rewrite_static( context: &RewriteContext<'_>, static_parts: &StaticParts<'_>, offset: Indent, -) -> Option { +) -> Result { // For now, if this static (or const) has generics, then bail. if static_parts .generics .is_some_and(|g| !g.params.is_empty() || !g.where_clause.is_empty()) { - return None; + return None.unknown_error(); } let colon = colon_spaces(context.config); @@ -2107,17 +2094,18 @@ fn rewrite_static( colon, ); // 2 = " =".len() - let ty_shape = - Shape::indented(offset.block_only(), context.config).offset_left_opt(prefix.len() + 2)?; - let ty_str = match static_parts.ty.rewrite(context, ty_shape) { - Some(ty_str) => ty_str, - None => { + let ty_shape = Shape::indented(offset.block_only(), context.config) + .offset_left_opt(prefix.len() + 2) + .unknown_error()?; + let ty_str = match static_parts.ty.rewrite_result(context, ty_shape) { + Ok(ty_str) => ty_str, + Err(_) => { if prefix.ends_with(' ') { prefix.pop(); } let nested_indent = offset.block_indent(context.config); let nested_shape = Shape::indented(nested_indent, context.config); - let ty_str = static_parts.ty.rewrite(context, nested_shape)?; + let ty_str = static_parts.ty.rewrite_result(context, nested_shape)?; format!( "{}{}", nested_indent.to_string_with_newline(context.config), @@ -2145,11 +2133,10 @@ fn rewrite_static( comments_span, true, ) - .ok() .map(|res| recover_comment_removed(res, static_parts.span, context)) .map(|s| if s.ends_with(';') { s } else { s + ";" }) } else { - Some(format!("{prefix}{ty_str};")) + Ok(format!("{prefix}{ty_str};")) } } @@ -2163,19 +2150,15 @@ struct OpaqueType<'a> { } impl<'a> Rewrite for OpaqueType<'a> { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - let shape = shape.offset_left_opt(5)?; // `impl ` + fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { + let shape = shape.offset_left_opt(5).unknown_error()?; // `impl ` self.bounds - .rewrite(context, shape) + .rewrite_result(context, shape) .map(|s| format!("impl {}", s)) } } impl Rewrite for ast::FnRetTy { - 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 { ast::FnRetTy::Default(_) => Ok(String::new()), @@ -2251,10 +2234,6 @@ fn get_missing_param_comments( } impl Rewrite for ast::Param { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { let param_attrs_result = self .attrs @@ -2421,11 +2400,7 @@ pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param } pub(crate) fn is_named_param(param: &ast::Param) -> bool { - if let ast::PatKind::Ident(_, ident, _) = param.pat.kind { - ident.name != symbol::kw::Empty - } else { - true - } + !matches!(param.pat.kind, ast::PatKind::Missing) } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -3323,9 +3298,9 @@ fn format_generics( offset: Indent, span: Span, used_width: usize, -) -> Option { +) -> Result { let shape = Shape::legacy(context.budget(used_width + offset.width()), offset); - let mut result = rewrite_generics(context, "", generics, shape).ok()?; + let mut result = rewrite_generics(context, "", generics, shape)?; // If the generics are not parameterized then generics.span.hi() == 0, // so we use span.lo(), which is the position after `struct Foo`. @@ -3351,8 +3326,7 @@ fn format_generics( Some(span.hi()), span_end_before_where, option, - ) - .ok()?; + )?; result.push_str(&where_clause_str); ( brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine, @@ -3391,7 +3365,7 @@ fn format_generics( !is_block }); if brace_pos == BracePos::None { - return Some(result); + return Ok(result); } let total_used_width = last_line_used_width(&result, used_width); let remaining_budget = context.budget(total_used_width); @@ -3414,14 +3388,10 @@ fn format_generics( } result.push('{'); - Some(result) + Ok(result) } impl Rewrite for ast::ForeignItem { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { let attrs_str = self.attrs.rewrite_result(context, shape)?; // Drop semicolon or it will be interpreted as comment. @@ -3585,7 +3555,7 @@ pub(crate) fn rewrite_extern_crate( pub(crate) fn is_mod_decl(item: &ast::Item) -> bool { !matches!( item.kind, - ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _)) + ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) ) } diff --git a/src/lib.rs b/src/lib.rs index 898689933e6..6a5a9c4f742 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ // N.B. these crates are loaded from the sysroot, so they need extern crate. extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_builtin_macros; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_expand; diff --git a/src/lists.rs b/src/lists.rs index 9d811e5d9b5..e23ff9df856 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -210,6 +210,7 @@ impl ListItem { pub(crate) enum Separator { Comma, VerticalBar, + Space, } impl Separator { @@ -219,6 +220,8 @@ impl Separator { Separator::Comma => 2, // 3 = ` | ` Separator::VerticalBar => 3, + // 1 = ` ` + Separator::Space => 1, } } } diff --git a/src/macros.rs b/src/macros.rs index 16897e57dcb..c3200ae850f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -9,12 +9,14 @@ // List-like invocations with parentheses will be formatted as function calls, // and those with brackets will be formatted as array literals. +use std::backtrace::Backtrace; use std::collections::HashMap; use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::sync::Arc; +use rustc_ast::ast; use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree}; -use rustc_ast::{ast, ptr}; use rustc_ast_pretty::pprust; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol}; use tracing::debug; @@ -28,7 +30,9 @@ use crate::expr::{RhsAssignKind, rewrite_array, rewrite_assign_rhs}; use crate::lists::{ListFormatting, itemize_list, write_list}; use crate::overflow; use crate::parse::macros::lazy_static::parse_lazy_static; -use crate::parse::macros::{ParsedMacroArgs, parse_expr, parse_macro_args}; +use crate::parse::macros::{ + ParsedMacroArgs, dioxus_rsx, html_extractor, parse_expr, parse_macro_args, yew_html, +}; use crate::rewrite::{ MacroErrorKind, Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult, }; @@ -53,10 +57,10 @@ pub(crate) enum MacroPosition { #[derive(Debug)] pub(crate) enum MacroArg { - Expr(ptr::P), - Ty(ptr::P), - Pat(ptr::P), - Item(ptr::P), + Expr(Box), + Ty(Box), + Pat(Box), + Item(Box), Keyword(Ident, Span), } @@ -70,10 +74,6 @@ 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; @@ -84,10 +84,6 @@ impl Rewrite for ast::Item { } 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_result(context, shape), @@ -239,6 +235,39 @@ fn rewrite_macro_inner( }, } } + if macro_name == "html_extractor::html!" || macro_name == "::html_extractor::html!" { + match html_extractor::format(context, shape, ts.clone()) { + Ok(rw) => return Ok(rw), + Err(err) => { + //tracing::error!("{} {}", err, context.snippet(mac.span())); + return Err(err); + } + } + } + if macro_name == "yew::html!" || macro_name == "::yew::html!" { + match yew_html::format( + mac.args.dspan.open, + mac.args.dspan.close, + context, + shape, + ts.clone(), + ) { + Ok(rw) => return Ok(rw), + Err(err) => { + //tracing::error!("{} {}", err, context.snippet(mac.span())); + return Err(err); + } + } + } + if macro_name == "rsx!" { + match dioxus_rsx::format(context, shape, ts.clone()) { + Ok(rw) => return Ok(rw), + Err(err) => { + //tracing::error!("{} {}", err, context.snippet(mac.span())); + return Err(err); + } + } + } let ParsedMacroArgs { args: arg_vec, @@ -720,7 +749,7 @@ fn last_tok(tt: &TokenTree) -> Token { match *tt { TokenTree::Token(ref t, _) => t.clone(), TokenTree::Delimited(delim_span, _, delim, _) => Token { - kind: TokenKind::CloseDelim(delim), + kind: delim.as_open_token_kind(), span: delim_span.close, }, } @@ -856,18 +885,18 @@ impl MacroArgParser { }; self.result.push(ParsedMacroArg { - kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()), + kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok), }); Some(()) } - fn update_buffer(&mut self, t: &Token) { + fn update_buffer(&mut self, t: Token) { if self.buf.is_empty() { - self.start_tok = t.clone(); + self.start_tok = t; } else { let needs_space = match next_space(&self.last_tok.kind) { - SpaceState::Ident => ident_like(t), - SpaceState::Punctuation => !ident_like(t), + SpaceState::Ident => ident_like(&t), + SpaceState::Punctuation => !ident_like(&t), SpaceState::Always => true, SpaceState::Never => false, }; @@ -876,7 +905,7 @@ impl MacroArgParser { } } - self.buf.push_str(&pprust::token_to_string(t)); + self.buf.push_str(&pprust::token_to_string(&t)); } fn need_space_prefix(&self) -> bool { @@ -935,7 +964,7 @@ impl MacroArgParser { ) if self.is_meta_var => { self.add_meta_variable(&mut iter)?; } - TokenTree::Token(ref t, _) => self.update_buffer(t), + &TokenTree::Token(t, _) => self.update_buffer(t), &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => { if !self.buf.is_empty() { if next_space(&self.last_tok.kind) == SpaceState::Always { @@ -1011,7 +1040,7 @@ fn wrap_macro_args_inner( } if !use_multiple_lines && result.len() >= shape.width { - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } else { Ok(result) } @@ -1122,8 +1151,14 @@ fn next_space(tok: &TokenKind) -> SpaceState { TokenKind::PathSep | TokenKind::Pound | TokenKind::Dollar - | TokenKind::OpenDelim(_) - | TokenKind::CloseDelim(_) => SpaceState::Never, + | TokenKind::OpenParen + | TokenKind::CloseParen + | TokenKind::OpenBrace + | TokenKind::CloseBrace + | TokenKind::OpenBracket + | TokenKind::CloseBracket + | TokenKind::OpenInvisible(_) + | TokenKind::CloseInvisible(_) => SpaceState::Never, TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(..) => { SpaceState::Ident @@ -1466,7 +1501,7 @@ fn rewrite_macro_with_items( Delimiter::Parenthesis => Ok(("(", ")")), Delimiter::Bracket => Ok(("[", "]")), Delimiter::Brace => Ok((" {", "}")), - _ => Err(RewriteError::Unknown), + _ => Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), }; let (opener, closer) = style_to_delims(style)?; @@ -1488,7 +1523,7 @@ fn rewrite_macro_with_items( for item in items { let item = match item { MacroArg::Item(item) => item, - _ => return Err(RewriteError::Unknown), + _ => return Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), }; visitor.visit_item(item); } diff --git a/src/matches.rs b/src/matches.rs index 1727a9de868..cb27f193d77 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,8 +1,10 @@ //! Format match expression. +use std::backtrace::Backtrace; use std::iter::repeat; +use std::sync::Arc; -use rustc_ast::{MatchKind, ast, ptr}; +use rustc_ast::{MatchKind, ast}; use rustc_span::{BytePos, Span}; use tracing::debug; @@ -55,10 +57,6 @@ impl<'a> Spanned for ArmWrapper<'a> { } impl<'a> Rewrite for ArmWrapper<'a> { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { rewrite_match_arm( context, @@ -378,6 +376,7 @@ fn flatten_arm_body<'a>( } } else { let cond_becomes_multi_line = opt_shape + .unknown_error() .and_then(|shape| rewrite_cond(context, expr, shape)) .map_or(false, |cond| cond.contains('\n')); if cond_becomes_multi_line { @@ -396,7 +395,7 @@ fn flatten_arm_body<'a>( fn rewrite_match_body( context: &RewriteContext<'_>, - body: &ptr::P, + body: &Box, pats_str: &str, shape: Shape, has_guard: bool, @@ -519,7 +518,7 @@ fn rewrite_match_body( .offset_left_opt(extra_offset(pats_str, shape) + 4) .and_then(|shape| shape.sub_width_opt(comma.len())); let orig_body = if forbid_same_line || !arrow_comment.is_empty() { - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } else if let Some(body_shape) = orig_body_shape { let rewrite = nop_block_collapse( format_expr(body, ExprType::Statement, context, body_shape), @@ -537,7 +536,7 @@ fn rewrite_match_body( _ => rewrite, } } else { - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) }; let orig_budget = orig_body_shape.map_or(0, |shape| shape.width); @@ -571,7 +570,7 @@ fn rewrite_match_body( // The `if ...` guard on a match arm. fn rewrite_guard( context: &RewriteContext<'_>, - guard: &Option>, + guard: &Option>, shape: Shape, // The amount of space used up on this line for the pattern in // the arm (excludes offset). diff --git a/src/modules.rs b/src/modules.rs index 4270f692910..b1d6394875b 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -26,7 +26,7 @@ type FileModMap<'ast> = BTreeMap>; #[derive(Debug, Clone)] pub(crate) struct Module<'a> { ast_mod_kind: Option>, - pub(crate) items: Cow<'a, ThinVec>>, + pub(crate) items: Cow<'a, ThinVec>>, inner_attr: ast::AttrVec, pub(crate) span: Span, } @@ -35,7 +35,7 @@ impl<'a> Module<'a> { pub(crate) fn new( mod_span: Span, ast_mod_kind: Option>, - mod_items: Cow<'a, ThinVec>>, + mod_items: Cow<'a, ThinVec>>, mod_attrs: Cow<'a, ast::AttrVec>, ) -> Self { let inner_attr = mod_attrs @@ -189,16 +189,16 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { /// Visit modules defined inside macro calls. fn visit_mod_outside_ast( &mut self, - items: ThinVec>, + items: ThinVec>, ) -> Result<(), ModuleResolutionError> { for item in items { if is_cfg_if(&item) { - self.visit_cfg_if(Cow::Owned(item.into_inner()))?; + self.visit_cfg_if(Cow::Owned(*item))?; continue; } if is_cfg_match(&item) { - self.visit_cfg_match(Cow::Owned(item.into_inner()))?; + self.visit_cfg_match(Cow::Owned(*item))?; continue; } @@ -221,7 +221,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { /// Visit modules from AST. fn visit_mod_from_ast( &mut self, - items: &'ast [rustc_ast::ptr::P], + items: &'ast [Box], ) -> Result<(), ModuleResolutionError> { for item in items { if is_cfg_if(item) { @@ -344,11 +344,12 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { self.directory = directory; } match (sub_mod.ast_mod_kind, sub_mod.items) { - (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => { + (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => { self.visit_mod_from_ast(items) } - (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _) - | (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items), + (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => { + self.visit_mod_outside_ast(items) + } (_, _) => Ok(()), } } diff --git a/src/overflow.rs b/src/overflow.rs index 19f7b06f8a3..59f81c6ef5b 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -3,8 +3,8 @@ use std::cmp::min; use itertools::Itertools; +use rustc_ast::ast; use rustc_ast::token::Delimiter; -use rustc_ast::{ast, ptr}; use rustc_span::Span; use tracing::debug; @@ -88,10 +88,6 @@ pub(crate) enum OverflowableItem<'a> { } impl<'a> Rewrite for OverflowableItem<'a> { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.map(|item| item.rewrite(context, shape)) - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { self.map(|item| item.rewrite_result(context, shape)) } @@ -219,7 +215,7 @@ pub(crate) trait IntoOverflowableItem<'a>: Rewrite + Spanned { fn into_overflowable_item(&'a self) -> OverflowableItem<'a>; } -impl<'a, T: 'a + IntoOverflowableItem<'a>> IntoOverflowableItem<'a> for ptr::P { +impl<'a, T: 'a + IntoOverflowableItem<'a>> IntoOverflowableItem<'a> for Box { fn into_overflowable_item(&'a self) -> OverflowableItem<'a> { (**self).into_overflowable_item() } @@ -432,9 +428,9 @@ impl<'a> Context<'a> { // If the argument consists of multiple closures, we do not overflow // the last closure. if closures::args_have_many_closure(&self.items) { - None + None.unknown_error() } else { - closures::rewrite_last_closure(self.context, expr, shape).ok() + closures::rewrite_last_closure(self.context, expr, shape) } } @@ -449,19 +445,19 @@ impl<'a> Context<'a> { .map_or(false, |cond| cond.contains('\n')); if multi_line { - None + None.unknown_error() } else { - expr.rewrite(self.context, shape) + expr.rewrite_result(self.context, shape) } } - _ => expr.rewrite(self.context, shape), + _ => expr.rewrite_result(self.context, shape), } } - item => item.rewrite(self.context, shape), + item => item.rewrite_result(self.context, shape), }; - if let Some(rewrite) = rewrite { + if let Ok(rewrite) = rewrite { // splitn(2, *).next().unwrap() is always safe. let rewrite_first_line = Ok(rewrite.splitn(2, '\n').next().unwrap().to_owned()); last_list_item.item = rewrite_first_line; @@ -545,13 +541,12 @@ impl<'a> Context<'a> { // formatted code, where a prefix or a suffix being left on its own // line. Here we explicitly check those cases. if count_newlines(overflowed) == 1 { - let rw = self - .items - .last() - .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape)); + let rw = self.items.last().unknown_error().and_then(|last_item| { + last_item.rewrite_result(self.context, self.nested_shape) + }); let no_newline = rw.as_ref().map_or(false, |s| !s.contains('\n')); if no_newline { - list_items[self.items.len() - 1].item = rw.unknown_error(); + list_items[self.items.len() - 1].item = rw; } else { list_items[self.items.len() - 1].item = Ok(overflowed.to_owned()); } @@ -563,11 +558,10 @@ impl<'a> Context<'a> { list_items[self.items.len() - 1].item = placeholder.unknown_error(); } _ if !self.items.is_empty() => { - list_items[self.items.len() - 1].item = self - .items - .last() - .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape)) - .unknown_error(); + list_items[self.items.len() - 1].item = + self.items.last().unknown_error().and_then(|last_item| { + last_item.rewrite_result(self.context, self.nested_shape) + }); // Use horizontal layout for a function with a single argument as long as // everything fits in a single line. diff --git a/src/pairs.rs b/src/pairs.rs index 48948b88b3b..9f178b2d209 100644 --- a/src/pairs.rs +++ b/src/pairs.rs @@ -3,6 +3,7 @@ use rustc_span::Span; use crate::config::IndentStyle; use crate::config::lists::*; +use crate::rewrite::RewriteError; use crate::rewrite::{Rewrite, RewriteContext, RewriteErrorExt, RewriteResult}; use crate::shape::Shape; use crate::spanned::Spanned; @@ -51,7 +52,6 @@ pub(crate) fn rewrite_all_pairs( } else { // First we try formatting on one line. rewrite_pairs_one_line(&list, shape, context) - .unknown_error() .or_else(|_| rewrite_pairs_multiline(&list, shape, context)) } }) @@ -63,7 +63,7 @@ fn rewrite_pairs_one_line( list: &PairList<'_, '_, T>, shape: Shape, context: &RewriteContext<'_>, -) -> Option { +) -> Result { assert!(list.list.len() >= 2, "Not a pair?"); let mut result = String::new(); @@ -72,7 +72,7 @@ fn rewrite_pairs_one_line( for ((_, rewrite), s) in list.list.iter().zip(list.separators.iter()) { if let Ok(rewrite) = rewrite { if !is_single_line(rewrite) || result.len() > shape.width { - return None; + return None.unknown_error(); } result.push_str(rewrite); @@ -80,18 +80,20 @@ fn rewrite_pairs_one_line( result.push_str(s); result.push(' '); } else { - return None; + return None.unknown_error(); } } let prefix_len = result.len(); - let last = list.list.last()?.0; - let cur_shape = base_shape.offset_left_opt(last_line_width(&result))?; - let last_rewrite = last.rewrite(context, cur_shape)?; + let last = list.list.last().unknown_error()?.0; + let cur_shape = base_shape + .offset_left_opt(last_line_width(&result)) + .unknown_error()?; + let last_rewrite = last.rewrite_result(context, cur_shape)?; result.push_str(&last_rewrite); if first_line_width(&result) > shape.width { - return None; + return None.unknown_error(); } // Check the last expression in the list. We sometimes let this expression @@ -99,7 +101,7 @@ fn rewrite_pairs_one_line( if !(is_single_line(&result) || last_rewrite.starts_with('{')) && (last_rewrite.starts_with('(') || prefix_len > context.config.tab_spaces()) { - return None; + return None.unknown_error(); } wrap_str(result, context.config.max_width(), shape) diff --git a/src/parse/macros/asm.rs b/src/parse/macros/asm.rs index 58c8d21bd7a..bfa9c6300c4 100644 --- a/src/parse/macros/asm.rs +++ b/src/parse/macros/asm.rs @@ -1,10 +1,10 @@ use rustc_ast::ast; -use rustc_builtin_macros::asm::{AsmArgs, parse_asm_args}; +use rustc_parse::parser::asm::{AsmArg, parse_asm_args}; use crate::rewrite::RewriteContext; #[allow(dead_code)] -pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option { +pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option> { let ts = mac.args.tokens.clone(); let mut parser = super::build_parser(context, ts); parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok() diff --git a/src/parse/macros/cfg_if.rs b/src/parse/macros/cfg_if.rs index 0b7b6c4d361..26bf6c5326f 100644 --- a/src/parse/macros/cfg_if.rs +++ b/src/parse/macros/cfg_if.rs @@ -1,7 +1,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind}; use rustc_ast::ast; -use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_ast::token::TokenKind; use rustc_parse::exp; use rustc_parse::parser::ForceCollect; use rustc_span::symbol::kw; @@ -60,11 +60,9 @@ fn parse_cfg_if_inner<'a>( return Err("Expected an opening brace"); } - while parser.token != TokenKind::CloseDelim(Delimiter::Brace) - && parser.token.kind != TokenKind::Eof - { + while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof { let item = match parser.parse_item(ForceCollect::No) { - Ok(Some(item_ptr)) => item_ptr.into_inner(), + Ok(Some(item_ptr)) => *item_ptr, Ok(None) => continue, Err(err) => { err.cancel(); diff --git a/src/parse/macros/cfg_match.rs b/src/parse/macros/cfg_match.rs index 87071db2749..c3d0e17865d 100644 --- a/src/parse/macros/cfg_match.rs +++ b/src/parse/macros/cfg_match.rs @@ -1,7 +1,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind}; use rustc_ast::ast; -use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_ast::token::TokenKind; use rustc_parse::exp; use rustc_parse::parser::ForceCollect; @@ -26,7 +26,7 @@ fn parse_cfg_match_inner<'a>( let ts = mac.args.tokens.clone(); let mut parser = build_stream_parser(psess.inner(), ts); - if parser.token == TokenKind::OpenDelim(Delimiter::Brace) { + if parser.token == TokenKind::OpenBrace { return Err("Expression position cfg_match! not yet supported"); } @@ -48,11 +48,9 @@ fn parse_cfg_match_inner<'a>( return Err("Expected an opening brace"); } - while parser.token != TokenKind::CloseDelim(Delimiter::Brace) - && parser.token.kind != TokenKind::Eof - { + while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof { let item = match parser.parse_item(ForceCollect::No) { - Ok(Some(item_ptr)) => item_ptr.into_inner(), + Ok(Some(item_ptr)) => *item_ptr, Ok(None) => continue, Err(err) => { err.cancel(); diff --git a/src/parse/macros/dioxus_rsx.rs b/src/parse/macros/dioxus_rsx.rs new file mode 100644 index 00000000000..f6be0fc30d7 --- /dev/null +++ b/src/parse/macros/dioxus_rsx.rs @@ -0,0 +1,359 @@ +use crate::expr::rewrite_literal; +use crate::rewrite::MacroErrorKind; +use crate::rewrite::Rewrite; +use crate::rewrite::RewriteContext; +use crate::rewrite::RewriteError; +use crate::rewrite::RewriteResult; +use crate::shape::Shape; +use rustc_ast::Block; +use rustc_ast::Pat; +use rustc_ast::Ty; +use rustc_ast::token::IdentIsRaw; +use rustc_ast::token::TokenKind; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{Expr, StrLit}; +use rustc_parse::exp; +use rustc_parse::parser::LetChainsPolicy; +use rustc_parse::parser::Parser; +use rustc_span::symbol::Ident; + +pub(crate) enum HtmlAttrName { + Ident((Ident, IdentIsRaw)), + Literal(StrLit), +} + +pub(crate) enum Html { + Expr(Box), + Literal(StrLit), + Element { + ty: Box, + attrs: Vec<(HtmlAttrName, Option>)>, + body: Vec, + }, + If { + conditional: Box, + body: Vec, + else_: Option>, + }, + For { + pattern: Box, + expr: Box, + body: Vec, + }, +} + +pub(crate) fn parse_single( + context: &RewriteContext<'_>, + ts_string: &str, + parser: &mut Parser<'_>, +) -> Result, RewriteError> { + macro_rules! parse_eat { + ($($arg:expr),*) => { + if !parser.eat($($arg,)*) { + panic!("{:?} {} {} {}", parser.token, file!(), line!(), ts_string); + } + } + } + let mut result = vec![]; + match &parser.token.kind { + TokenKind::Ident(symbol, _) if symbol.as_str() == "if" => { + assert!(parser.eat_keyword(exp!(If))); + let conditional = match parser.parse_expr_cond(LetChainsPolicy::AlwaysAllowed) { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(OpenBrace))); + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + let some_htmls = parse_single(context, ts_string, parser)?; + body.extend(some_htmls); + } + assert!(parser.eat(exp!(CloseBrace))); + + let else_ = if parser.eat_keyword(exp!(Else)) { + assert!(parser.eat(exp!(OpenBrace))); + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + let some_htmls = parse_single(context, ts_string, parser)?; + body.extend(some_htmls); + } + assert!(parser.eat(exp!(CloseBrace))); + + Some(body) + } else { + None + }; + + result.push(Html::If { + conditional, + body, + else_, + }) + } + TokenKind::Ident(symbol, _) if symbol.as_str() == "for" => { + assert!(parser.eat_keyword(exp!(For))); + let (pattern, expr) = match parser.parse_for_head() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(OpenBrace))); + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + let some_htmls = parse_single(context, ts_string, parser)?; + body.extend(some_htmls); + } + assert!(parser.eat(exp!(CloseBrace))); + + result.push(Html::For { + pattern, + expr, + body, + }) + } + TokenKind::OpenBrace => { + let expr = match parser.parse_block() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + result.push(Html::Expr(expr)) + } + TokenKind::Literal(_) => { + let Ok(literal) = parser.parse_str_lit() else { + panic!(); + }; + result.push(Html::Literal(literal)) + } + TokenKind::Ident(_, _) => { + let ty = parser.parse_ty().map_err(|d| { + let err = RewriteError::MacroFailure { + kind: MacroErrorKind::ParseFailure, + span: d.span.primary_span().unwrap(), + }; + d.cancel(); + err + })?; + parse_eat!(exp!(OpenBrace)); + let mut attrs = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace + && parser.look_ahead(1, |token| { + token.kind == TokenKind::Colon + || token.kind == TokenKind::Comma + || (!matches!(parser.token.kind, TokenKind::Literal(_)) + && token.kind == TokenKind::CloseBrace) + }) + { + // parse attribute + let attr_name = if parser.token.is_ident() { + let name = HtmlAttrName::Ident(parser.token.ident().unwrap()); + parser.bump(); // TODO FIXME + name + } else if let TokenKind::Literal(_lit) = parser.token.kind { + // TODO FIXME this needs to have a colon value. + let name = HtmlAttrName::Literal(parser.parse_str_lit().unwrap()); + name + } else { + panic!("{:?}", parser.token.kind); + }; + let value = if parser.token.kind == TokenKind::Colon { + assert!(parser.eat(exp!(Colon))); + let expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + Some(expr) + } else { + None + }; + attrs.push((attr_name, value)); + if parser.token.kind == TokenKind::Comma { + assert!(parser.eat(exp!(Comma))); + } else { + break; + } + } + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + let some_htmls = parse_single(context, ts_string, parser)?; + body.extend(some_htmls); + // optional commas are allowed + if parser.token.kind == TokenKind::Comma { + assert!(parser.eat(exp!(Comma))); + } + } + assert!(parser.eat(exp!(CloseBrace))); + result.push(Html::Element { ty, attrs, body }); + } + other => panic!("unexpected token {:?} {}", other, ts_string), + } + Ok(result) +} + +pub(crate) fn parse( + context: &RewriteContext<'_>, + ts: TokenStream, +) -> Result, RewriteError> { + let ts_string = format!("{:?}", ts); + let mut result = vec![]; + let mut parser = super::build_parser(context, ts); + while parser.token.kind != TokenKind::Eof { + let val = parse_single(context, &ts_string, &mut parser).expect(&ts_string); + result.extend(val); + } + Ok(result) +} + +fn format_inner(context: &RewriteContext<'_>, mut shape: Shape, html: &Html) -> RewriteResult { + let mut result = String::new(); + match html { + Html::Literal(literal) => { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str(&rewrite_literal( + context, + literal.as_token_lit(), + literal.span, + Shape::indented(shape.indent, context.config), + )?); + } + Html::Expr(p) => { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str(&p.rewrite_result( + context, + Shape::indented(shape.indent, context.config).sub_width(1, p.span)?, + )?); + } + Html::Element { ty, attrs, body } => { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str(&ty.rewrite_result( + context, + Shape::indented(shape.indent, context.config).sub_width(1, ty.span)?, + )?); + result.push_str(" {"); + shape.indent = shape.indent.block_indent(context.config); + for (name, value) in attrs { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + match name { + HtmlAttrName::Ident((ident, ident_is_raw)) => match ident_is_raw { + IdentIsRaw::No => result.push_str(ident.as_str()), + IdentIsRaw::Yes => { + result.push_str("r#"); + result.push_str(ident.as_str()) + } + }, + HtmlAttrName::Literal(lit) => result.push_str(&rewrite_literal( + context, + lit.as_token_lit(), + lit.span, + Shape::indented(shape.indent, context.config), + )?), + } + if let Some(value) = value { + result.push_str(": "); + result.push_str(&value.rewrite_result( + context, + Shape::indented(shape.indent, context.config).sub_width(1, value.span)?, + )?); + } + result.push_str(","); + } + for child in body { + result.push_str(&format_inner(context, shape, child)?); + } + shape.indent = shape.indent.block_unindent(context.config); + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str("}"); + } + Html::If { + conditional, + body, + else_, + } => { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str("if "); + result.push_str(&conditional.rewrite_result( + context, + Shape::indented(shape.indent, context.config).sub_width(1, conditional.span)?, + )?); + result.push_str(" {"); + shape.indent = shape.indent.block_indent(context.config); + let inner_result = format_vec(context, shape, body)?; + result.push_str(&inner_result); + shape.indent = shape.indent.block_unindent(context.config); + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str("}"); + if let Some(body) = else_ { + result.push_str(" else {"); + shape.indent = shape.indent.block_indent(context.config); + let inner_result = format_vec(context, shape, body)?; + result.push_str(&inner_result); + shape.indent = shape.indent.block_unindent(context.config); + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str("}"); + } + } + Html::For { + pattern, + expr, + body, + } => { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str("for "); + result.push_str(&pattern.rewrite_result( + context, + Shape::indented(shape.indent, context.config).sub_width(1, pattern.span)?, + )?); + result.push_str(" in "); + result.push_str(&expr.rewrite_result( + context, + Shape::indented(shape.indent, context.config).sub_width(1, expr.span)?, + )?); + result.push_str(" {"); + shape.indent = shape.indent.block_indent(context.config); + let inner_result = format_vec(context, shape, body)?; + result.push_str(&inner_result); + shape.indent = shape.indent.block_unindent(context.config); + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push_str("}"); + } + } + Ok(result.to_string()) +} + +fn format_vec(context: &RewriteContext<'_>, shape: Shape, elems: &Vec) -> RewriteResult { + let mut result = String::new(); + + for html in elems { + let inner_result = format_inner(context, shape, html)?; + result.push_str(&inner_result); + } + + Ok(result.clone()) +} + +pub(crate) fn format( + context: &RewriteContext<'_>, + mut shape: Shape, + ts: TokenStream, +) -> RewriteResult { + let mut result = String::new(); + + result.push_str("rsx! {"); + shape.indent = shape.indent.block_indent(context.config); + + let parsed_elems = parse(context, ts)?; + + result.push_str(&format_vec(context, shape, &parsed_elems)?); + + shape.indent = shape.indent.block_unindent(context.config); + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push('}'); + + Ok(result) +} diff --git a/src/parse/macros/html_extractor.rs b/src/parse/macros/html_extractor.rs new file mode 100644 index 00000000000..258770f070e --- /dev/null +++ b/src/parse/macros/html_extractor.rs @@ -0,0 +1,734 @@ +use crate::config::lists::DefinitiveListTactic; +use crate::config::lists::ListTactic; +use crate::config::lists::SeparatorTactic; +use crate::expr::rewrite_literal; +use crate::lists::ListFormatting; +use crate::lists::ListItem; +use crate::lists::Separator; +use crate::lists::definitive_tactic; +use crate::lists::itemize_list; +use crate::lists::write_list; +use crate::rewrite::Rewrite; +use crate::rewrite::RewriteContext; +use crate::rewrite::RewriteResult; +use crate::shape::Indent; +use crate::shape::Shape; +use crate::vertical::AlignedItem; +use itertools::Itertools; +use rustc_ast::Block; +use rustc_ast::token::TokenKind; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{Expr, StrLit}; +use rustc_parse::exp; +use rustc_parse::parser::LetChainsPolicy; +use rustc_parse::parser::Parser; +use rustc_span::symbol::Ident; + +pub(crate) enum HtmlAttributeValue { + Expr(Box), + Literal(StrLit), + Ident(Ident), +} + +pub(crate) struct HtmlAttr { + base_ident: Ident, + rest_ident: Vec<(TokenKind, Ident)>, + value: HtmlAttributeValue, +} + +impl AlignedItem for HtmlAttr { + fn skip(&self) -> bool { + false + } + + fn get_span(&self) -> rustc_span::Span { + self.base_ident.span + } + + fn rewrite_prefix(&self, _context: &RewriteContext<'_>, _shape: Shape) -> RewriteResult { + let mut result = String::new(); + result.push_str(self.base_ident.as_str()); + result.push_str( + &self + .rest_ident + .iter() + .map(|(delimiter, ident)| { + match delimiter { + TokenKind::Colon => ":", + TokenKind::Minus => "-", + _ => panic!(), + } + .to_owned() + + ident.as_str() + }) + .join(""), + ); + Ok(result) + } + + fn rewrite_aligned_item( + &self, + context: &RewriteContext<'_>, + shape: Shape, + _prefix_max_width: usize, + ) -> RewriteResult { + let mut result = String::new(); + result.push_str(self.base_ident.as_str()); + result.push_str( + &self + .rest_ident + .iter() + .map(|(delimiter, ident)| { + match delimiter { + TokenKind::Colon => ":", + TokenKind::Minus => "-", + _ => panic!(), + } + .to_owned() + + ident.as_str() + }) + .join(""), + ); + result.push_str("="); + match &self.value { + HtmlAttributeValue::Expr(p) => { + result.push_str("{"); + result.push_str( + &p.rewrite_result( + context, + Shape::indented(shape.indent.block_indent(context.config), context.config) + .sub_width(result.len() + 3, p.span)?, + ) + .unwrap(), + ); + result.push_str("}"); + } + HtmlAttributeValue::Literal(str_lit) => { + result.push_str(&rewrite_literal( + context, + str_lit.as_token_lit(), + str_lit.span, + shape, + )?); + } + HtmlAttributeValue::Ident(ident) => result.push_str(ident.as_str()), + } + Ok(result) + } +} + +pub(crate) enum Html { + Expr(Box), + Literal(StrLit), + Ident(Ident), + Open { + tag: Ident, + attrs: Vec, + }, + Close { + tag: Ident, + }, + If { + conditional: Box, + body: Vec, + variable: Ident, + result_expr: Box, + else_: Option<(Vec, Box)>, + }, + While { + conditional: Box, + body: Vec, + variable: Ident, + result_expr: Box, + }, + Let { + variable: Ident, + expr: Box, + }, + Use(Box), + Extern(Box), +} + +pub(crate) fn parse_single_html( + context: &RewriteContext<'_>, + ts_string: &str, + parser: &mut Parser<'_>, +) -> Option> { + macro_rules! parse_eat { + ($($arg:expr),*) => { + if !parser.eat($($arg,)*) { + panic!("{:?} {} {}", parser.token, file!(), line!()); + } + } + } + let mut result = vec![]; + match &parser.token.kind { + TokenKind::Ident(symbol, _) if symbol.as_str() == "use" => { + assert!(parser.eat_keyword(exp!(Use))); + let expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(Semi))); + result.push(Html::Use(expr)); + } + TokenKind::Ident(symbol, _) if symbol.as_str() == "extern" => { + assert!(parser.eat_keyword(exp!(Extern))); + let block = match parser.parse_block() { + Ok(block) => block, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + result.push(Html::Extern(block)); + } + TokenKind::Ident(symbol, _) if symbol.as_str() == "let" => { + assert!(parser.eat_keyword(exp!(Let))); + let variable = parser.token.ident().unwrap().0; + parser.bump(); + assert!(parser.eat(exp!(Eq))); + + match &parser.token.kind { + TokenKind::Ident(symbol, _) if symbol.as_str() == "if" => { + assert!(parser.eat_keyword(exp!(If))); + let conditional = match parser.parse_expr_cond(LetChainsPolicy::AlwaysAllowed) { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(OpenBrace))); + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + if let Some(some_htmls) = parse_single_html(context, ts_string, parser) { + body.extend(some_htmls); + } else { + panic!(); + } + } + assert!(parser.eat(exp!(CloseBrace))); + assert!(parser.eat(exp!(FatArrow))); + + let result_expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + + let else_ = if parser.eat_keyword(exp!(Else)) { + assert!(parser.eat(exp!(OpenBrace))); + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + if let Some(some_htmls) = parse_single_html(context, ts_string, parser) + { + body.extend(some_htmls); + } else { + panic!(); + } + } + assert!(parser.eat(exp!(CloseBrace))); + assert!(parser.eat(exp!(FatArrow))); + + let result_expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + Some((body, result_expr)) + } else { + None + }; + assert!(parser.eat(exp!(Semi))); + + result.push(Html::If { + conditional, + body, + variable, + result_expr, + else_, + }) + } + TokenKind::Ident(symbol, _) if symbol.as_str() == "while" => { + assert!(parser.eat_keyword(exp!(While))); + let conditional = match parser.parse_expr_cond(LetChainsPolicy::AlwaysAllowed) { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(OpenBrace))); + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + if let Some(some_htmls) = parse_single_html(context, ts_string, parser) { + body.extend(some_htmls); + } else { + panic!(); + } + } + assert!(parser.eat(exp!(CloseBrace))); + assert!(parser.eat(exp!(FatArrow))); + let result_expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(Semi))); + result.push(Html::While { + conditional, + body, + variable, + result_expr, + }) + } + _ => { + let expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(Semi))); + result.push(Html::Let { variable, expr }) + } + } + } + TokenKind::OpenBrace => { + assert!(parser.eat(exp!(OpenBrace))); + let expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(CloseBrace))); + result.push(Html::Expr(expr)) + } + TokenKind::Literal(_) => { + let Ok(literal) = parser.parse_str_lit() else { + panic!(); + }; + result.push(Html::Literal(literal)) + } + TokenKind::Ident(_, _) => { + let ident = parser.token.ident().unwrap().0; + parser.bump(); + result.push(Html::Ident(ident)) + } + TokenKind::Lt => { + parse_eat!(exp!(Lt)); + match parser.token.kind { + TokenKind::Slash => { + parser.bump(); + let id = parser.token.ident().unwrap().0; + parser.bump(); + parse_eat!(exp!(Gt)); + result.push(Html::Close { tag: id }); + } + _ => { + let id = parser.token.ident().expect(&ts_string).0; + parser.bump(); + let mut attrs: Vec = Vec::new(); + while parser.token.kind != TokenKind::Gt { + let base_id = parser.token.ident().expect(&ts_string).0; + parser.bump(); + let mut rest_id = Vec::new(); + while parser.token.kind == TokenKind::Colon + || parser.token.kind == TokenKind::Minus + { + let delimiter = parser.token.kind.clone(); + parser.bump(); + let i = parser.token.ident().unwrap().0; + parser.bump(); + rest_id.push((delimiter, i)); + } + parse_eat!(exp!(Eq)); + match &parser.token.kind { + TokenKind::OpenBrace => { + assert!(parser.eat(exp!(OpenBrace))); + let expr = match parser.parse_expr() { + Ok(expr) => expr, + Err(error) => { + panic!("{:?} {:?}", error, parser.parse_tokens()); + } + }; + assert!(parser.eat(exp!(CloseBrace))); + attrs.push(HtmlAttr { + base_ident: base_id, + rest_ident: rest_id, + value: HtmlAttributeValue::Expr(expr), + }); + } + TokenKind::Literal(_) => { + let Ok(literal) = parser.parse_str_lit() else { + panic!(); + }; + attrs.push(HtmlAttr { + base_ident: base_id, + rest_ident: rest_id, + value: HtmlAttributeValue::Literal(literal), + }); + } + TokenKind::Ident(_, _) => { + let ident = parser.token.ident().unwrap().0; + parser.bump(); + attrs.push(HtmlAttr { + base_ident: base_id, + rest_ident: rest_id, + value: HtmlAttributeValue::Ident(ident), + }) + } + _ => panic!(), + } + } + parse_eat!(exp!(Gt)); + result.push(Html::Open { tag: id, attrs }); + } + } + } + other => panic!("unexpected token {:?} {}", other, ts_string), + } + Some(result) +} + +pub(crate) fn parse_html(context: &RewriteContext<'_>, ts: TokenStream) -> Option> { + let ts_string = format!("{:?}", ts); + let mut result = vec![]; + let mut parser = super::build_parser(context, ts); + while parser.token.kind != TokenKind::Eof { + if let Some(val) = parse_single_html(context, &ts_string, &mut parser) { + result.extend(val); + } else { + panic!(); + } + } + + Some(result) +} + +fn format_html_extractor_html_inner( + context: &RewriteContext<'_>, + shape: Shape, + indent: &mut Indent, + result: &mut String, + html: &Html, +) -> RewriteResult { + match html { + Html::Literal(literal) => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str(&rewrite_literal( + context, + literal.as_token_lit(), + literal.span, + Shape::indented(*indent, context.config), + )?); + } + Html::Ident(ident) => { + if ident.as_str() != "_" { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str(ident.as_str()); + } + } + Html::Expr(p) => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("{"); + result.push_str( + &p.rewrite_result( + context, + Shape::indented(*indent, context.config).sub_width(1, p.span)?, + ) + .unwrap(), + ); + result.push_str("}"); + } + Html::Open { tag, attrs } => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("<"); + result.push_str(tag.as_str()); + if attrs.len() > 0 { + let item_shape = Shape::indented(*indent, context.config); + + let mut items = itemize_list( + context.snippet_provider, + attrs.iter(), + "\n", + "", + |field| field.get_span().lo(), + |field| field.get_span().hi(), + |field| field.rewrite_aligned_item(context, item_shape, 0), + tag.span.lo(), + tag.span.hi(), + false, + ) + .collect::>(); + + let tactic = definitive_tactic( + &items, + ListTactic::HorizontalVertical, + Separator::Space, + item_shape.width.saturating_sub(1), + ); + + if tactic == DefinitiveListTactic::Horizontal { + // since the items fits on a line, there is no need to align them + let do_rewrite = |field: &HtmlAttr| -> RewriteResult { + field.rewrite_aligned_item(context, item_shape, 0) + }; + attrs.iter().zip(items.iter_mut()).for_each( + |(field, list_item): (&HtmlAttr, &mut ListItem)| { + if list_item.item.is_ok() { + list_item.item = do_rewrite(field); + } + }, + ); + } + + let fmt = ListFormatting::new( + Shape::indented(indent.block_indent(context.config), context.config), + context.config, + ) + .separator("") + .tactic(tactic) + .trailing_separator(SeparatorTactic::Never) + .ends_with_newline(true) + .preserve_newline(true); + let the_result = write_list(&items, &fmt)?; + if the_result.contains("\n") { + result.push_str( + &indent + .block_indent(context.config) + .to_string_with_newline(context.config), + ); + } else { + result.push_str(" "); + } + result.push_str(&the_result); + if the_result.contains("\n") { + result.push_str(&indent.to_string_with_newline(context.config)); + } + } + result.push_str(">"); + *indent = indent.block_indent(context.config); + } + Html::Close { tag } => { + *indent = indent.block_unindent(context.config); + if ![ + "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", + "link", "meta", "param", "source", "track", "wbr", + ] + .contains(&tag.as_str()) + { + result.push_str(&indent.to_string_with_newline(context.config)); + } + result.push_str(""); + } + Html::If { + conditional, + body, + variable, + result_expr, + else_, + } => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("let "); + result.push_str(variable.as_str()); + result.push_str(" = "); + result.push_str("if "); + result.push_str( + &conditional.rewrite_result( + context, + Shape::indented(*indent, context.config) + // TODO FIXME calculate rest of line? + .sub_width( + 10 + variable.as_str().len() + indent.block_indent, + conditional.span, + )?, + )?, + ); + result.push_str(" {"); + *indent = indent.block_indent(context.config); + let indent_after = &mut indent.clone(); + format_html_extractor_html_vec(context, shape, indent_after, result, body)?; + *indent = indent.block_unindent(context.config); + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("} "); + result.push_str("=> "); + result.push_str(&result_expr.rewrite_result( + context, + Shape::indented(*indent, context.config).sub_width(1, result_expr.span)?, + )?); + if let Some((body, result_expr)) = else_ { + result.push_str(" else {"); + *indent = indent.block_indent(context.config); + format_html_extractor_html_vec(context, shape, &mut indent.clone(), result, body)?; + *indent = indent.block_unindent(context.config); + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("} => "); + result.push_str( + &result_expr + .rewrite_result( + context, + Shape::indented(*indent, context.config) + .sub_width(1, result_expr.span)?, + ) + .unwrap(), + ); + } + result.push_str(";"); + *indent = *indent_after; + *indent = indent.block_unindent(context.config); + } + Html::While { + conditional, + body, + variable, + result_expr, + } => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("let "); + result.push_str(variable.as_str()); + result.push_str(" = "); + result.push_str("while "); + result.push_str( + &conditional + .rewrite_result( + context, + Shape::indented(*indent, context.config).sub_width(1, conditional.span)?, + ) + .unwrap(), + ); + result.push_str(" {"); + *indent = indent.block_indent(context.config); + format_html_extractor_html_vec(context, shape, &mut indent.clone(), result, body)?; + *indent = indent.block_unindent(context.config); + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("} => "); + result.push_str( + &result_expr + .rewrite_result( + context, + Shape::indented(*indent, context.config).sub_width(1, result_expr.span)?, + ) + .unwrap(), + ); + result.push_str(";"); + } + Html::Let { variable, expr } => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("let "); + result.push_str(variable.as_str()); + result.push_str(" = "); + result.push_str( + &expr + .rewrite_result( + context, + Shape::indented(*indent, context.config).sub_width(1, expr.span)?, + ) + .unwrap(), + ); + result.push_str(";"); + } + Html::Use(expr) => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("use "); + result.push_str( + &expr + .rewrite_result( + context, + Shape::indented(*indent, context.config).sub_width(1, expr.span)?, + ) + .unwrap(), + ); + result.push_str(";"); + } + Html::Extern(block) => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("extern "); + result.push_str( + &block + .rewrite_result( + context, + Shape::indented(*indent, context.config).sub_width(1, block.span)?, + ) + .unwrap(), + ); + } + } + Ok(result.to_string()) +} + +fn format_html_extractor_html_vec( + context: &RewriteContext<'_>, + shape: Shape, + indent: &mut Indent, + result: &mut String, + elems: &Vec, +) -> RewriteResult { + let mut min_indent = 0; + let mut indent_amount = 0; + + for elem in elems.iter() { + indent_amount += match elem { + Html::Expr(_) => 0, + Html::Literal(_) => 0, + Html::Ident(_) => 0, + Html::Open { tag: _, attrs: _ } => -1, + Html::Close { tag: _ } => 1, + Html::If { + conditional: _, + body: _, + variable: _, + result_expr: _, + else_: _, + } => 0, + Html::While { + conditional: _, + body: _, + variable: _, + result_expr: _, + } => 0, + Html::Let { + variable: _, + expr: _, + } => 0, + Html::Use(_expr) => 0, + Html::Extern(_block) => 0, + }; + min_indent = std::cmp::max(min_indent, indent_amount); + } + + for _ in 0..min_indent { + *indent = indent.block_indent(context.config); + } + + for html in elems { + format_html_extractor_html_inner(context, shape, indent, result, html)?; + } + + for _ in 0..min_indent { + *indent = indent.block_unindent(context.config); + } + + Ok(result.clone()) +} + +pub(crate) fn format(context: &RewriteContext<'_>, shape: Shape, ts: TokenStream) -> RewriteResult { + let mut result = String::new(); + + result.push_str("html_extractor::html! {"); + + let parsed_elems = parse_html(context, ts).unwrap(); + let mut indent = shape.indent.block_indent(context.config); + format_html_extractor_html_vec(context, shape, &mut indent, &mut result, &parsed_elems)?; + + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push('}'); + + Ok(result) +} diff --git a/src/parse/macros/lazy_static.rs b/src/parse/macros/lazy_static.rs index cbe81004e22..8611615d123 100644 --- a/src/parse/macros/lazy_static.rs +++ b/src/parse/macros/lazy_static.rs @@ -1,5 +1,4 @@ use rustc_ast::ast; -use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_parse::exp; @@ -10,7 +9,7 @@ use crate::rewrite::RewriteContext; pub(crate) fn parse_lazy_static( context: &RewriteContext<'_>, ts: TokenStream, -) -> Option, P)>> { +) -> Option, Box)>> { let mut result = vec![]; let mut parser = super::build_parser(context, ts); macro_rules! parse_or { diff --git a/src/parse/macros/mod.rs b/src/parse/macros/mod.rs index 8a956faf03b..654855a946f 100644 --- a/src/parse/macros/mod.rs +++ b/src/parse/macros/mod.rs @@ -1,6 +1,6 @@ +use rustc_ast::ast; use rustc_ast::token::{Delimiter, NonterminalKind, NtExprKind::*, NtPatKind::*, TokenKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ast, ptr}; use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::parser::{ForceCollect, Parser, Recovery}; use rustc_session::parse::ParseSess; @@ -12,7 +12,10 @@ use crate::rewrite::RewriteContext; pub(crate) mod asm; pub(crate) mod cfg_if; pub(crate) mod cfg_match; +pub(crate) mod dioxus_rsx; +pub(crate) mod html_extractor; pub(crate) mod lazy_static; +pub(crate) mod yew_html; fn build_stream_parser<'a>(psess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> { Parser::new(psess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden) @@ -50,26 +53,26 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { Expr, NonterminalKind::Expr(Expr), |parser: &mut Parser<'b>| parser.parse_expr(), - |x: ptr::P| Some(x) + |x: Box| Some(x) ); parse_macro_arg!( Ty, NonterminalKind::Ty, |parser: &mut Parser<'b>| parser.parse_ty(), - |x: ptr::P| Some(x) + |x: Box| Some(x) ); parse_macro_arg!( Pat, NonterminalKind::Pat(PatParam { inferred: false }), |parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None), - |x: ptr::P| Some(x) + |x: Box| Some(x) ); - // `parse_item` returns `Option>`. + // `parse_item` returns `Option>`. parse_macro_arg!( Item, NonterminalKind::Item, |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No), - |x: Option>| x + |x: Option>| x ); None @@ -165,7 +168,7 @@ pub(crate) fn parse_macro_args( pub(crate) fn parse_expr( context: &RewriteContext<'_>, tokens: TokenStream, -) -> Option> { +) -> Option> { let mut parser = build_parser(context, tokens); parser.parse_expr().ok() } diff --git a/src/parse/macros/yew_html.rs b/src/parse/macros/yew_html.rs new file mode 100644 index 00000000000..11c534a071a --- /dev/null +++ b/src/parse/macros/yew_html.rs @@ -0,0 +1,644 @@ +use crate::Indent; +use crate::rewrite::MacroErrorKind; +use crate::rewrite::Rewrite as _; +use crate::rewrite::RewriteContext; +use crate::rewrite::RewriteError; +use crate::rewrite::RewriteResult; +use crate::shape::Shape; +use crate::utils::mk_sp; +use itertools::Either; +use itertools::Itertools as _; +use rustc_ast::Block; +use rustc_ast::Ty; +use rustc_ast::token::TokenKind; +use rustc_ast::token::TokenKind::Slash; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{Expr, StrLit}; +use rustc_parse::exp; +use rustc_parse::parser::LetChainsPolicy; +use rustc_parse::parser::Parser; +use rustc_span::Span; +use rustc_span::Symbol; +use rustc_span::symbol::Ident; + +enum HtmlAttributeValue { + Expr(Box), + Literal(StrLit), + Ident(Ident), +} + +struct HtmlIf { + conditional: Box, + body: Vec, + else_: Option, Vec>>, +} + +enum Html { + Expr(Box), + Literal(StrLit), + Ident(Ident), + Open { + start_span: Span, + tag: Option>, + attrs: Vec<(Ident, Vec<(TokenKind, Ident)>, HtmlAttributeValue)>, + self_closing: bool, + end_span: Span, + }, + Close { + start_span: Span, + tag: Option>, + end_span: Span, + }, + If { + start_span: Span, + before_body: Span, + inner: HtmlIf, + after_body: Span, + end_span: Span, + }, +} + +fn parse_single_html( + context: &RewriteContext<'_>, + ts_string: &str, + parser: &mut Parser<'_>, +) -> Result, RewriteError> { + macro_rules! check { + ($arg:expr) => { + if !$arg { + return Err(RewriteError::MacroFailure { + kind: MacroErrorKind::ParseFailure, + span: parser.token.span, + }); + } + }; + } + macro_rules! parse_or { + ($method:ident $(,)* $($arg:expr),* $(,)*) => { + match parser.$method($($arg,)*) { + Ok(val) => { + if parser.psess.dcx().has_errors().is_some() { + parser.psess.dcx().reset_err_count(); + return Err(RewriteError::MacroFailure { + kind: MacroErrorKind::ParseFailure, + span: parser.token.span, + }); + } else { + val + } + } + Err(err) => { + err.cancel(); + parser.psess.dcx().reset_err_count(); + return Err(RewriteError::MacroFailure { + kind: MacroErrorKind::ParseFailure, + span: parser.token.span, + }); + } + } + } + } + let mut result = vec![]; + match &parser.token.kind { + TokenKind::Ident(symbol, _) if symbol.as_str() == "if" => { + let start_span = parser.token.span; + check!(parser.eat_keyword(exp!(If))); + let conditional = parse_or!(parse_expr_cond, LetChainsPolicy::AlwaysAllowed); + check!(parser.eat(exp!(OpenBrace))); + let before_body = parser.token.span; + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + body.extend(parse_single_html(context, ts_string, parser)?); + } + let after_body = parser.token.span; + check!(parser.eat(exp!(CloseBrace))); + + let else_ = if parser.eat_keyword(exp!(Else)) { + if parser.token.is_ident_named(Symbol::intern("if")) { + Some(Either::Left(parse_single_html(context, ts_string, parser)?)) + } else { + check!(parser.eat(exp!(OpenBrace))); + let mut body = Vec::new(); + while parser.token.kind != TokenKind::CloseBrace { + body.extend(parse_single_html(context, ts_string, parser)?); + } + check!(parser.eat(exp!(CloseBrace))); + Some(Either::Right(body)) + } + } else { + None + }; + + let end_span = parser.token.span; + + result.push(Html::If { + start_span, + before_body, + inner: HtmlIf { + conditional, + body, + else_, + }, + after_body, + end_span, + }) + } + TokenKind::OpenBrace => { + let expr = parse_or!(parse_block); + result.push(Html::Expr(expr)) + } + TokenKind::Literal(_) => { + let Ok(literal) = parser.parse_str_lit() else { + panic!(); + }; + result.push(Html::Literal(literal)) + } + TokenKind::Ident(_, _) => { + let ident = parser.token.ident().unwrap().0; + parser.bump(); + result.push(Html::Ident(ident)) + } + TokenKind::Lt => { + let start_span = parser.token.span; + check!(parser.eat(exp!(Lt))); + match parser.token.kind { + TokenKind::Slash => { + parser.bump(); + if parser.token.kind == TokenKind::Gt { + let end_span = parser.token.span; + check!(parser.eat(exp!(Gt))); + result.push(Html::Close { + start_span, + tag: None, + end_span, + }); + } else { + let id = parse_or!(parse_ty); + let end_span = parser.token.span; + check!(parser.eat(exp!(Gt))); + result.push(Html::Close { + start_span, + tag: Some(id), + end_span, + }); + } + } + TokenKind::Gt => { + let end_span = parser.token.span; + check!(parser.eat(exp!(Gt))); + result.push(Html::Open { + start_span, + tag: None, + attrs: Vec::new(), + self_closing: false, + end_span, + }); + } + _ => { + let ty = parse_or!(parse_ty); + let mut attrs: Vec<(Ident, Vec<(TokenKind, Ident)>, HtmlAttributeValue)> = + Vec::new(); + while parser.token.kind != TokenKind::Gt && parser.token.kind != Slash { + let Some((base_id, _)) = parser.token.ident() else { + return Err(RewriteError::MacroFailure { + kind: MacroErrorKind::ParseFailure, + span: parser.token.span, + }); + }; + parser.bump(); + let mut rest_id = Vec::new(); + while parser.token.kind == TokenKind::Colon + || parser.token.kind == TokenKind::Minus + { + let delimiter = parser.token.kind.clone(); + parser.bump(); + let i = parser.token.ident().unwrap().0; + parser.bump(); + rest_id.push((delimiter, i)); + } + check!(parser.eat(exp!(Eq))); + match &parser.token.kind { + TokenKind::OpenBrace => { + check!(parser.eat(exp!(OpenBrace))); + let expr = parse_or!(parse_expr); + check!(parser.eat(exp!(CloseBrace))); + attrs.push((base_id, rest_id, HtmlAttributeValue::Expr(expr))); + } + TokenKind::Literal(_) => { + let Ok(literal) = parser.parse_str_lit() else { + panic!(); + }; + attrs.push(( + base_id, + rest_id, + HtmlAttributeValue::Literal(literal), + )); + } + TokenKind::Ident(_, _) => { + let ident = parser.token.ident().unwrap().0; + parser.bump(); + attrs.push((base_id, rest_id, HtmlAttributeValue::Ident(ident))) + } + _ => panic!(), + } + } + if parser.token.kind == Slash { + parser.bump(); + let end_span = parser.token.span; + check!(parser.eat(exp!(Gt))); + result.push(Html::Open { + start_span, + tag: Some(ty), + attrs, + self_closing: true, + end_span, + }); + } else { + let end_span = parser.token.span; + check!(parser.eat(exp!(Gt))); + result.push(Html::Open { + start_span, + tag: Some(ty), + attrs, + self_closing: false, + end_span, + }); + } + } + } + } + _other => { + return Err(RewriteError::MacroFailure { + kind: MacroErrorKind::ParseFailure, + span: parser.token.span, + }); + } + } + Ok(result) +} + +fn parse_html(context: &RewriteContext<'_>, ts: TokenStream) -> Result, RewriteError> { + let ts_string = format!("{:?}", ts); + let mut result = vec![]; + let mut parser = super::build_parser(context, ts); + while parser.token.kind != TokenKind::Eof { + result.extend(parse_single_html(context, &ts_string, &mut parser)?); + } + + Ok(result) +} + +fn format_yew_html_inner( + context: &RewriteContext<'_>, + shape: Shape, + indent: &mut Indent, + result: &mut String, + html: &Html, +) -> RewriteResult { + match html { + Html::Literal(literal) => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("\""); + result.push_str(literal.symbol.as_str().trim_ascii()); + result.push_str("\""); + } + Html::Ident(ident) => { + if ident.as_str() != "_" { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str(ident.as_str()); + } + } + Html::Expr(p) => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str( + &p.rewrite_result(context, Shape::indented(*indent, context.config)) + .unwrap(), + ); + } + Html::Open { + start_span: _, + tag, + attrs, + self_closing, + end_span: _, + } => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("<"); + if let Some(tag) = tag { + result.push_str( + &tag.rewrite_result(context, Shape::indented(*indent, context.config)) + .unwrap(), + ); + } + for (base_ident, rest_ident, value) in attrs { + result.push_str(" "); + result.push_str(base_ident.as_str()); + result.push_str( + &rest_ident + .iter() + .map(|(delimiter, ident)| { + match delimiter { + TokenKind::Colon => ":", + TokenKind::Minus => "-", + _ => panic!(), + } + .to_owned() + + ident.as_str() + }) + .join(""), + ); + result.push_str("="); + match &value { + HtmlAttributeValue::Expr(p) => { + result.push_str("{"); + result.push_str( + &p.rewrite_result(context, Shape::indented(*indent, context.config)) + .unwrap(), + ); + result.push_str("}"); + } + HtmlAttributeValue::Literal(str_lit) => { + result.push_str("\""); + result.push_str(str_lit.symbol.as_str()); + result.push_str("\""); + } + HtmlAttributeValue::Ident(ident) => result.push_str(ident.as_str()), + } + } + if *self_closing { + result.push_str(" /"); + } + result.push_str(">"); + if !*self_closing { + *indent = indent.block_indent(context.config); + } + } + Html::Close { + start_span: _, + tag, + end_span: _, + } => { + *indent = indent.block_unindent(context.config); + if let Some(tag) = tag { + let tag_text = context.snippet(tag.span); + if ![ + "area", "base", "br", "col", "command", "embed", "hr", "img", "input", + "keygen", "link", "meta", "param", "source", "track", "wbr", + ] + .contains(&tag_text) + { + result.push_str(&indent.to_string_with_newline(context.config)); + } + } + if result.ends_with("\n") { + result.push_str(&indent.to_string(context.config)); + } + result.push_str(""); + } + Html::If { + start_span: _, + before_body, + inner: + HtmlIf { + conditional, + body, + else_, + }, + after_body, + end_span, + } => { + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("if "); + result.push_str( + &conditional + .rewrite_result(context, Shape::indented(*indent, context.config)) + .unwrap(), + ); + result.push_str(" {"); + *indent = indent.block_indent(context.config); + let indent_after = &mut indent.clone(); + format_yew_html_vec( + *before_body, + *after_body, + context, + shape, + indent_after, + result, + body, + ) + .unwrap(); + *indent = indent.block_unindent(context.config); + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("}"); + match else_ { + None => {} + Some(Either::Left(left)) => { + result.push_str(" else "); + format_yew_html_vec( + *after_body, + *end_span, + context, + shape, + &mut indent.clone(), + result, + left, + ) + .unwrap(); + *indent = indent.block_unindent(context.config); + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("}"); + } + Some(Either::Right(right)) => { + result.push_str(" else {"); + *indent = indent.block_indent(context.config); + format_yew_html_vec( + *after_body, + *end_span, + context, + shape, + &mut indent.clone(), + result, + right, + ) + .unwrap(); + *indent = indent.block_unindent(context.config); + result.push_str(&indent.to_string_with_newline(context.config)); + result.push_str("}"); + } + } + *indent = *indent_after; + *indent = indent.block_unindent(context.config); + } + } + Ok(result.to_string()) +} + +fn format_yew_html_vec( + start_span: Span, + end_span: Span, + context: &RewriteContext<'_>, + shape: Shape, + indent: &mut Indent, + result: &mut String, + elems: &Vec, +) -> RewriteResult { + let mut min_indent = 0; + let mut indent_amount = 0; + + for elem in elems.iter() { + indent_amount += match elem { + Html::Expr(_) => 0, + Html::Literal(_) => 0, + Html::Ident(_) => 0, + Html::Open { + start_span: _, + tag: _, + attrs: _, + self_closing: _, + end_span: _, + } => -1, + Html::Close { + start_span: _, + tag: _, + end_span: _, + } => 1, + Html::If { + start_span: _, + before_body: _, + inner: + HtmlIf { + conditional: _, + body: _, + else_: _, + }, + after_body: _, + end_span: _, + } => 0, + }; + min_indent = std::cmp::max(min_indent, indent_amount); + } + + for _ in 0..min_indent { + *indent = indent.block_indent(context.config); + } + + let low_spans: Vec<_> = std::iter::once(start_span) + .chain(elems.iter().map(|elem| match elem { + Html::Expr(p) => p.span.shrink_to_hi(), + Html::Literal(str_lit) => str_lit.span.shrink_to_hi(), + Html::Ident(ident) => ident.span.shrink_to_hi(), + Html::Open { + start_span: _, + tag: _, + attrs: _, + self_closing: _, + end_span, + } => end_span.shrink_to_hi(), + Html::Close { + start_span: _, + tag: _, + end_span, + } => end_span.shrink_to_hi(), + Html::If { + start_span: _, + before_body: _, + after_body: _, + inner: _, + end_span, + } => end_span.shrink_to_hi(), + })) + .collect(); + let high_spans: Vec<_> = elems + .iter() + .map(|elem| match elem { + Html::Expr(p) => p.span.shrink_to_lo(), + Html::Literal(str_lit) => str_lit.span.shrink_to_lo(), + Html::Ident(ident) => ident.span.shrink_to_lo(), + Html::Open { + start_span, + tag: _, + attrs: _, + self_closing: _, + end_span: _, + } => start_span.shrink_to_lo(), + Html::Close { + start_span, + tag: _, + end_span: _, + } => start_span.shrink_to_lo(), + Html::If { + start_span, + before_body: _, + after_body: _, + inner: _, + end_span: _, + } => start_span.shrink_to_lo(), + }) + .chain(std::iter::once(end_span)) + .collect(); + for i in 0..elems.len() { + let html = &elems[i]; + let span_between_elem = mk_sp(low_spans[i].hi(), high_spans[i].lo()); + let comment = crate::comment::recover_missing_comment_in_span( + span_between_elem, + Shape::indented(*indent, context.config), + context, + 0, + )?; + result.push_str(&comment); + if !comment.is_empty() { + result.push_str("\n"); + } + format_yew_html_inner(context, shape, indent, result, html).unwrap(); + } + let span_between_elem = mk_sp(low_spans[elems.len()].hi(), high_spans[elems.len()].lo()); + let comment = crate::comment::recover_missing_comment_in_span( + span_between_elem, + Shape::indented(*indent, context.config), + context, + 0, + )?; + result.push_str(&comment); + + for _ in 0..min_indent { + *indent = indent.block_unindent(context.config); + } + + Ok(result.clone()) +} + +pub(crate) fn format( + start_span: Span, + end_span: Span, + context: &RewriteContext<'_>, + shape: Shape, + ts: TokenStream, +) -> RewriteResult { + let mut result = String::new(); + + result.push_str("::yew::html! {"); + + let parsed_elems = parse_html(context, ts)?; + let mut indent = shape.indent.block_indent(context.config); + format_yew_html_vec( + start_span.shrink_to_hi(), + end_span.shrink_to_lo(), + context, + shape, + &mut indent, + &mut result, + &parsed_elems, + )?; + + result.push_str(&shape.indent.to_string_with_newline(context.config)); + result.push('}'); + + Ok(result) +} diff --git a/src/parse/parser.rs b/src/parse/parser.rs index f357aed66c2..2ec8769c45f 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -1,7 +1,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind}; use std::path::{Path, PathBuf}; -use rustc_ast::{ast, attr, ptr}; +use rustc_ast::{ast, attr}; use rustc_errors::Diag; use rustc_parse::parser::Parser as RawParser; use rustc_parse::{exp, new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; @@ -102,7 +102,7 @@ impl<'a> Parser<'a> { psess: &'a ParseSess, path: &Path, span: Span, - ) -> Result<(ast::AttrVec, ThinVec>, Span), ParserError> { + ) -> Result<(ast::AttrVec, ThinVec>, Span), ParserError> { let result = catch_unwind(AssertUnwindSafe(|| { let mut parser = unwrap_or_emit_fatal(new_parser_from_file(psess.inner(), path, Some(span))); diff --git a/src/parse/session.rs b/src/parse/session.rs index afd847f9515..10e2809e58b 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination}; use rustc_errors::registry::Registry; -use rustc_errors::translation::Translate; +use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel}; use rustc_session::parse::ParseSess as RawParseSess; use rustc_span::{ @@ -47,16 +47,6 @@ impl SilentOnIgnoredFilesEmitter { } } -impl Translate for SilentOnIgnoredFilesEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - self.emitter.fluent_bundle() - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - self.emitter.fallback_fluent_bundle() - } -} - impl Emitter for SilentOnIgnoredFilesEmitter { fn source_map(&self) -> Option<&SourceMap> { None @@ -84,6 +74,10 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } self.handle_non_ignoreable_error(diag, registry); } + + fn translator(&self) -> &Translator { + self.emitter.translator() + } } impl From for ColorConfig { @@ -110,23 +104,15 @@ fn default_dcx( ColorConfig::Never }; - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - let emitter = Box::new( - HumanEmitter::new(stderr_destination(emit_color), fallback_bundle) - .sm(Some(source_map.clone())), - ); - - let emitter: Box = if !show_parse_errors { - Box::new(SilentEmitter { - fatal_emitter: emitter, - fatal_note: None, - emit_fatal_diagnostic: false, - }) + let translator = rustc_driver::default_translator(); + + let emitter: Box = if show_parse_errors { + Box::new( + HumanEmitter::new(stderr_destination(emit_color), translator) + .sm(Some(source_map.clone())), + ) } else { - emitter + Box::new(SilentEmitter { translator }) }; DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter { has_non_ignorable_parser_errors: false, @@ -205,7 +191,7 @@ impl ParseSess { } pub(crate) fn set_silent_emitter(&mut self) { - self.raw_psess.dcx().make_silent(None, false); + self.raw_psess.dcx().make_silent(); } pub(crate) fn span_to_filename(&self, span: Span) -> FileName { @@ -335,16 +321,6 @@ mod tests { num_emitted_errors: Arc, } - impl Translate for TestEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - panic!("test emitter attempted to translate a diagnostic"); - } - } - impl Emitter for TestEmitter { fn source_map(&self) -> Option<&SourceMap> { None @@ -353,6 +329,10 @@ mod tests { fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } + + fn translator(&self) -> &Translator { + panic!("test emitter attempted to translate a diagnostic"); + } } fn build_diagnostic(level: DiagnosticLevel, span: Option) -> DiagInner { diff --git a/src/patterns.rs b/src/patterns.rs index 80daad75fec..f2f3a99215b 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -1,5 +1,7 @@ +use std::backtrace::Backtrace; +use std::sync::Arc; + use rustc_ast::ast::{self, BindingMode, ByRef, Pat, PatField, PatKind, RangeEnd, RangeSyntax}; -use rustc_ast::ptr; use rustc_span::{BytePos, Span}; use crate::comment::{FindUncommented, combine_strs_with_missing_comments}; @@ -42,6 +44,7 @@ pub(crate) fn is_short_pattern( fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool { match &pat.kind { + ast::PatKind::Missing => unreachable!(), ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => { true } @@ -76,15 +79,11 @@ fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool } pub(crate) struct RangeOperand<'a, T> { - pub operand: &'a Option>, + pub operand: &'a Option>, pub span: Span, } impl<'a, T: Rewrite> Rewrite for RangeOperand<'a, T> { - 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.operand { None => Ok("".to_owned()), @@ -94,12 +93,9 @@ impl<'a, T: Rewrite> Rewrite for RangeOperand<'a, T> { } impl Rewrite for Pat { - 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.kind { + PatKind::Missing => unreachable!(), PatKind::Or(ref pats) => { let pat_strs = pats .iter() @@ -257,7 +253,7 @@ impl Rewrite for Pat { }) } } - PatKind::Never => Err(RewriteError::Unknown), + PatKind::Never => Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), PatKind::Range(ref lhs, ref rhs, ref end_kind) => { rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span) } @@ -302,7 +298,7 @@ impl Rewrite for Pat { qself, path, fields, - rest == ast::PatFieldsRest::Rest, + matches!(rest, ast::PatFieldsRest::Rest(_)), self.span, context, shape, @@ -315,8 +311,8 @@ impl Rewrite for Pat { ) .map(|inner_pat| format!("({})", inner_pat)), PatKind::Guard(..) => Ok(context.snippet(self.span).to_string()), - PatKind::Deref(_) => Err(RewriteError::Unknown), - PatKind::Err(_) => Err(RewriteError::Unknown), + PatKind::Deref(_) => Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), + PatKind::Err(_) => Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), } } } @@ -324,8 +320,8 @@ impl Rewrite for Pat { pub(crate) fn rewrite_range_pat( context: &RewriteContext<'_>, shape: Shape, - lhs: &Option>, - rhs: &Option>, + lhs: &Option>, + rhs: &Option>, end_kind: &rustc_span::source_map::Spanned, span: Span, ) -> RewriteResult { @@ -366,7 +362,7 @@ pub(crate) fn rewrite_range_pat( } fn rewrite_struct_pat( - qself: &Option>, + qself: &Option>, path: &ast::Path, fields: &[ast::PatField], ellipsis: bool, @@ -449,10 +445,6 @@ fn rewrite_struct_pat( } impl Rewrite for PatField { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { let hi_pos = if let Some(last) = self.attrs.last() { last.span.hi() @@ -504,15 +496,11 @@ impl Rewrite for PatField { #[derive(Debug)] pub(crate) enum TuplePatField<'a> { - Pat(&'a ptr::P), + Pat(&'a Box), Dotdot(Span), } impl<'a> Rewrite for TuplePatField<'a> { - 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 { TuplePatField::Pat(p) => p.rewrite_result(context, shape), @@ -561,7 +549,7 @@ pub(crate) fn can_be_overflowed_pat( } fn rewrite_tuple_pat( - pats: &[ptr::P], + pats: &[Box], path_str: Option, span: Span, context: &RewriteContext<'_>, diff --git a/src/reorder.rs b/src/reorder.rs index e9d0fc059f8..dccfa11e358 100644 --- a/src/reorder.rs +++ b/src/reorder.rs @@ -6,7 +6,9 @@ // FIXME(#2455): Reorder trait items. +use std::backtrace::Backtrace; use std::cmp::Ordering; +use std::sync::Arc; use rustc_ast::{ast, attr}; use rustc_span::{Span, symbol::sym}; @@ -16,7 +18,7 @@ use crate::config::{Config, GroupImportsTactic}; use crate::imports::{UseSegmentKind, UseTree, normalize_use_trees_with_granularity}; use crate::items::{is_mod_decl, rewrite_extern_crate, rewrite_mod}; use crate::lists::{ListFormatting, ListItem, itemize_list, write_list}; -use crate::rewrite::{RewriteContext, RewriteError, RewriteResult}; +use crate::rewrite::{RewriteContext, RewriteError, RewriteErrorExt, RewriteResult}; use crate::shape::Shape; use crate::sort::version_sort; use crate::source_map::LineRangeUtils; @@ -87,7 +89,7 @@ fn rewrite_reorderable_item( match item.kind { ast::ItemKind::ExternCrate(..) => rewrite_extern_crate(context, item, shape), ast::ItemKind::Mod(_, ident, _) => rewrite_mod(context, item, ident, shape), - _ => Err(RewriteError::Unknown), + _ => Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), } } @@ -316,10 +318,10 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.shape(), span, ); - self.push_rewrite(span, rw.ok()); + self.push_rewrite(span, rw); } else { for item in items { - self.push_rewrite(item.span, None); + self.push_rewrite(item.span, None.unknown_error()); } } diff --git a/src/rewrite.rs b/src/rewrite.rs index 7ca1ca522ff..8481302cccb 100644 --- a/src/rewrite.rs +++ b/src/rewrite.rs @@ -1,9 +1,10 @@ // A generic trait to abstract the rewriting of an element (of the AST). +use std::backtrace::Backtrace; use std::cell::{Cell, RefCell}; use std::rc::Rc; +use std::sync::Arc; -use rustc_ast::ptr; use rustc_span::Span; use thiserror::Error; @@ -16,17 +17,12 @@ use crate::visitor::SnippetProvider; pub(crate) type RewriteResult = Result; pub(crate) trait Rewrite { - /// Rewrite self into shape. - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option; - - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { - self.rewrite(context, shape).unknown_error() - } + fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult; } -impl Rewrite for ptr::P { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - (**self).rewrite(context, shape) +impl Rewrite for Box { + fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { + (**self).rewrite_result(context, shape) } } @@ -59,8 +55,37 @@ pub(crate) enum RewriteError { MacroFailure { kind: MacroErrorKind, span: Span }, /// Format failure that does not fit to above categories. - #[error("An unknown error occurred during formatting.")] - Unknown, + #[error("An unknown error occurred during formatting. {0}")] + Unknown(Arc), +} + +impl PartialEq for RewriteError { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ( + Self::ExceedsMaxWidth { + configured_width: l_configured_width, + span: l_span, + }, + Self::ExceedsMaxWidth { + configured_width: r_configured_width, + span: r_span, + }, + ) => l_configured_width == r_configured_width && l_span == r_span, + ( + Self::MacroFailure { + kind: l_kind, + span: l_span, + }, + Self::MacroFailure { + kind: r_kind, + span: r_span, + }, + ) => l_kind == r_kind && l_span == r_span, + (Self::Unknown(_), Self::Unknown(_)) => true, + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } } pub(crate) struct ExceedsMaxWidthError { @@ -100,7 +125,7 @@ impl RewriteErrorExt for Option { } fn unknown_error(self) -> Result { - self.ok_or_else(|| RewriteError::Unknown) + self.ok_or_else(|| RewriteError::Unknown(Arc::new(Backtrace::capture()))) } } diff --git a/src/spanned.rs b/src/spanned.rs index 507647566d4..020651e2daa 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -1,6 +1,6 @@ use std::cmp::max; -use rustc_ast::{ast, ptr}; +use rustc_ast::ast; use rustc_span::{Span, source_map}; use crate::macros::MacroArg; @@ -12,7 +12,7 @@ pub(crate) trait Spanned { fn span(&self) -> Span; } -impl Spanned for ptr::P { +impl Spanned for Box { fn span(&self) -> Span { (**self).span() } @@ -122,7 +122,7 @@ impl Spanned for ast::GenericParam { fn span(&self) -> Span { let lo = match self.kind { _ if !self.attrs.is_empty() => self.attrs[0].span.lo(), - ast::GenericParamKind::Const { kw_span, .. } => kw_span.lo(), + ast::GenericParamKind::Const { span, .. } => span.lo(), _ => self.ident.span.lo(), }; let hi = if self.bounds.is_empty() { diff --git a/src/stmt.rs b/src/stmt.rs index 76194421c84..28d5e1bf9e6 100644 --- a/src/stmt.rs +++ b/src/stmt.rs @@ -1,3 +1,6 @@ +use std::backtrace::Backtrace; +use std::sync::Arc; + use rustc_ast::ast; use rustc_span::Span; @@ -89,10 +92,6 @@ impl<'a> Stmt<'a> { } impl<'a> Rewrite for Stmt<'a> { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result( &self, context: &RewriteContext<'_>, @@ -136,7 +135,7 @@ fn format_stmt( format_expr(ex, expr_type, context, shape).map(|s| s + suffix) } ast::StmtKind::MacCall(..) | ast::StmtKind::Item(..) | ast::StmtKind::Empty => { - Err(RewriteError::Unknown) + Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))) } }; result.map(|res| recover_comment_removed(res, stmt.span(), context)) diff --git a/src/string.rs b/src/string.rs index 3b971188cd5..53239871ec8 100644 --- a/src/string.rs +++ b/src/string.rs @@ -5,6 +5,7 @@ use unicode_properties::{GeneralCategory, UnicodeGeneralCategory}; use unicode_segmentation::UnicodeSegmentation; use crate::config::Config; +use crate::rewrite::{RewriteError, RewriteErrorExt}; use crate::shape::Shape; use crate::utils::{unicode_str_width, wrap_str}; @@ -65,9 +66,9 @@ pub(crate) fn rewrite_string<'a>( orig: &str, fmt: &StringFormat<'a>, newline_max_chars: usize, -) -> Option { - let max_width_with_indent = fmt.max_width_with_indent()?; - let max_width_without_indent = fmt.max_width_without_indent()?; +) -> Result { + let max_width_with_indent = fmt.max_width_with_indent().unknown_error()?; + let max_width_without_indent = fmt.max_width_without_indent().unknown_error()?; let indent_with_newline = fmt.shape.indent.to_string_with_newline(fmt.config); let indent_without_newline = fmt.shape.indent.to_string(fmt.config); @@ -377,6 +378,7 @@ fn graphemes_width(graphemes: &[&str]) -> usize { mod test { use super::{SnippetState, StringFormat, break_string, detect_url, rewrite_string}; use crate::config::Config; + use crate::rewrite::RewriteErrorExt; use crate::shape::{Indent, Shape}; use unicode_segmentation::UnicodeSegmentation; @@ -384,7 +386,7 @@ mod test { fn issue343() { let config = Default::default(); let fmt = StringFormat::new(Shape::legacy(2, Indent::empty()), &config); - rewrite_string("eq_", &fmt, 2); + assert_eq!(rewrite_string("eq_", &fmt, 2), None.unknown_error()); } #[test] @@ -505,7 +507,7 @@ mod test { let rewritten_string = rewrite_string(string, &fmt, 27); assert_eq!( rewritten_string, - Some("\"Nulla\nconsequat erat at massa. \\\n Vivamus id mi.\"".to_string()) + Ok("\"Nulla\nconsequat erat at massa. \\\n Vivamus id mi.\"".to_string()) ); } @@ -517,11 +519,11 @@ mod test { fmt.trim_end = true; let rewritten_string = rewrite_string(string, &fmt, 25); - assert_eq!(rewritten_string, Some("\"Vivamus id mi.\"".to_string())); + assert_eq!(rewritten_string, Ok("\"Vivamus id mi.\"".to_string())); fmt.trim_end = false; // default value of trim_end let rewritten_string = rewrite_string(string, &fmt, 25); - assert_eq!(rewritten_string, Some("\"Vivamus id mi. \"".to_string())); + assert_eq!(rewritten_string, Ok("\"Vivamus id mi. \"".to_string())); } #[test] @@ -541,7 +543,7 @@ mod test { let rewritten_string = rewrite_string(string, &fmt, 100); assert_eq!( rewritten_string, - Some("Vivamus id mi.\n // Vivamus id mi.".to_string()) + Ok("Vivamus id mi.\n // Vivamus id mi.".to_string()) ); } @@ -561,7 +563,7 @@ mod test { assert_eq!( rewrite_string(comment, &fmt, 30), - Some( + Ok( "Aenean metus.\n // Vestibulum ac lacus. Vivamus\n // porttitor" .to_string() ) @@ -584,7 +586,7 @@ mod test { assert_eq!( rewrite_string(comment, &fmt, 30), - Some( + Ok( "Aenean metus.\n // Vestibulum ac lacus. Vivamus@\n // porttitor" .to_string() ) @@ -607,23 +609,19 @@ mod test { let comment = "Aenean metus. Vestibulum\n\nac lacus. Vivamus porttitor"; assert_eq!( rewrite_string(comment, &fmt, 30), - Some( - "Aenean metus. Vestibulum\n //\n // ac lacus. Vivamus porttitor".to_string() - ) + Ok("Aenean metus. Vestibulum\n //\n // ac lacus. Vivamus porttitor".to_string()) ); fmt.shape = Shape::legacy(15, Indent::from_width(&config, 4)); let comment = "Aenean\n\nmetus. Vestibulum ac lacus. Vivamus porttitor"; assert_eq!( rewrite_string(comment, &fmt, 15), - Some( - r#"Aenean + Ok(r#"Aenean // // metus. Vestibulum // ac lacus. Vivamus // porttitor"# - .to_string() - ) + .to_string()) ); } @@ -643,21 +641,19 @@ mod test { let comment = "Aenean\n\nmetus. Vestibulum ac lacus.\n\n"; assert_eq!( rewrite_string(comment, &fmt, 20), - Some( - "Aenean\n //\n // metus. Vestibulum ac\n // lacus.\n //\n".to_string() - ) + Ok("Aenean\n //\n // metus. Vestibulum ac\n // lacus.\n //\n".to_string()) ); let comment = "Aenean\n\nmetus. Vestibulum ac lacus.\n"; assert_eq!( rewrite_string(comment, &fmt, 20), - Some("Aenean\n //\n // metus. Vestibulum ac\n // lacus.\n".to_string()) + Ok("Aenean\n //\n // metus. Vestibulum ac\n // lacus.\n".to_string()) ); let comment = "Aenean\n \nmetus. Vestibulum ac lacus."; assert_eq!( rewrite_string(comment, &fmt, 20), - Some("Aenean\n //\n // metus. Vestibulum ac\n // lacus.".to_string()) + Ok("Aenean\n //\n // metus. Vestibulum ac\n // lacus.".to_string()) ); } @@ -677,14 +673,14 @@ mod test { let comment = "Aenean metus. Vestibulum ac lacus."; assert_eq!( rewrite_string(comment, &fmt, 13), - Some("Aenean metus.\n // Vestibulum ac\n // lacus.".to_string()) + Ok("Aenean metus.\n // Vestibulum ac\n // lacus.".to_string()) ); fmt.trim_end = false; let comment = "Vestibulum ac lacus."; assert_eq!( rewrite_string(comment, &fmt, 13), - Some("Vestibulum \n // ac lacus.".to_string()) + Ok("Vestibulum \n // ac lacus.".to_string()) ); fmt.trim_end = true; @@ -692,7 +688,7 @@ mod test { let comment = "Vestibulum ac lacus."; assert_eq!( rewrite_string(comment, &fmt, 13), - Some("Vestibulum\\\n // ac lacus.".to_string()) + Ok("Vestibulum\\\n // ac lacus.".to_string()) ); } diff --git a/src/types.rs b/src/types.rs index 76f176c97c4..c77cfcb797e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,8 @@ +use std::backtrace::Backtrace; use std::ops::Deref; +use std::sync::Arc; use rustc_ast::ast::{self, FnRetTy, Mutability, Term}; -use rustc_ast::ptr; use rustc_span::{BytePos, Pos, Span, symbol::kw}; use tracing::debug; @@ -39,7 +40,7 @@ pub(crate) enum PathContext { pub(crate) fn rewrite_path( context: &RewriteContext<'_>, path_context: PathContext, - qself: &Option>, + qself: &Option>, path: &ast::Path, shape: Shape, ) -> RewriteResult { @@ -169,10 +170,6 @@ impl<'a> Spanned for SegmentParam<'a> { } impl<'a> Rewrite for SegmentParam<'a> { - 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 { SegmentParam::Const(const_) => const_.rewrite_result(context, shape), @@ -184,10 +181,6 @@ impl<'a> Rewrite for SegmentParam<'a> { } impl Rewrite for ast::PreciseCapturingArg { - 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 { ast::PreciseCapturingArg::Lifetime(lt) => lt.rewrite_result(context, shape), @@ -199,10 +192,6 @@ impl Rewrite for ast::PreciseCapturingArg { } impl Rewrite for ast::AssocItemConstraint { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { use ast::AssocItemConstraintKind::{Bound, Equality}; @@ -239,10 +228,6 @@ impl Rewrite for ast::AssocItemConstraint { } impl Rewrite for ast::AssocItemConstraintKind { - 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 { ast::AssocItemConstraintKind::Equality { term } => match term { @@ -456,10 +441,6 @@ fn get_tactics(item_vec: &[ListItem], output: &str, shape: Shape) -> DefinitiveL } impl Rewrite for ast::WherePredicate { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { let attrs_str = self.attrs.rewrite_result(context, shape)?; // FIXME: dead spans? @@ -472,7 +453,7 @@ impl Rewrite for ast::WherePredicate { }) => { let type_str = bounded_ty.rewrite_result(context, shape)?; let colon = type_bound_colon(context).trim_end(); - let lhs = if let Some(binder_str) = + let lhs = if let Ok(binder_str) = rewrite_bound_params(context, shape, bound_generic_params) { format!("for<{binder_str}> {type_str}{colon}") @@ -535,10 +516,6 @@ impl Rewrite for ast::WherePredicate { } impl Rewrite for ast::GenericArg { - 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 { ast::GenericArg::Lifetime(ref lt) => lt.rewrite_result(context, shape), @@ -613,30 +590,18 @@ fn rewrite_bounded_lifetime( } impl Rewrite for ast::AnonConst { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { format_expr(&self.value, ExprType::SubExpression, context, shape) } } impl Rewrite for ast::Lifetime { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, _: Shape) -> RewriteResult { Ok(context.snippet(self.ident.span).to_owned()) } } impl Rewrite for ast::GenericBound { - 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 { ast::GenericBound::Trait(ref poly_trait_ref) => { @@ -655,10 +620,6 @@ impl Rewrite for ast::GenericBound { } impl Rewrite for ast::GenericBounds { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { if self.is_empty() { return Ok(String::new()); @@ -669,10 +630,6 @@ impl Rewrite for ast::GenericBounds { } impl Rewrite for ast::GenericParam { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { // FIXME: If there are more than one attributes, this will force multiline. let mut result = self @@ -685,7 +642,7 @@ impl Rewrite for ast::GenericParam { let param_start = if let ast::GenericParamKind::Const { ref ty, - kw_span, + span, default, } = &self.kind { @@ -707,7 +664,7 @@ impl Rewrite for ast::GenericParam { default.rewrite_result(context, Shape::legacy(budget, shape.indent))?; param.push_str(&rewrite); } - kw_span.lo() + span.lo() } else { param.push_str(rewrite_ident(context, self.ident)); self.ident.span.lo() @@ -762,12 +719,8 @@ impl Rewrite for ast::GenericParam { } impl Rewrite for ast::PolyTraitRef { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { - let (binder, shape) = if let Some(lifetime_str) = + let (binder, shape) = if let Ok(lifetime_str) = rewrite_bound_params(context, shape, &self.bound_generic_params) { // 6 is "for<> ".len() @@ -802,20 +755,12 @@ impl Rewrite for ast::PolyTraitRef { } impl Rewrite for ast::TraitRef { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.rewrite_result(context, shape).ok() - } - fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { rewrite_path(context, PathContext::Type, &None, &self.path, shape) } } impl Rewrite for ast::Ty { - 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.kind { ast::TyKind::TraitObject(ref bounds, tobj_syntax) => { @@ -825,10 +770,6 @@ impl Rewrite for ast::Ty { let shape = shape.offset_left(4, self.span())?; (shape, "dyn ") } - ast::TraitObjectSyntax::DynStar => { - let shape = shape.offset_left(5, self.span())?; - (shape, "dyn* ") - } ast::TraitObjectSyntax::None => (shape, ""), }; let mut res = bounds.rewrite_result(context, shape)?; @@ -1003,7 +944,7 @@ impl Rewrite for ast::Ty { }) } } - ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape), + ast::TyKind::FnPtr(ref fn_ptr) => rewrite_fn_ptr(fn_ptr, self.span, context, shape), ast::TyKind::Never => Ok(String::from("!")), ast::TyKind::MacCall(ref mac) => { rewrite_macro(mac, context, shape, MacroPosition::Expression) @@ -1044,7 +985,7 @@ impl Rewrite for ast::Ty { // We always want to write `unsafe<>` since `unsafe<> Ty` // and `Ty` are distinct types. result.push_str("unsafe<> ") - } else if let Some(ref lifetime_str) = + } else if let Ok(ref lifetime_str) = rewrite_bound_params(context, shape, &binder.generic_params) { result.push_str("unsafe<"); @@ -1069,22 +1010,31 @@ impl Rewrite for ast::Ty { } impl Rewrite for ast::TyPat { - 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.kind { ast::TyPatKind::Range(ref lhs, ref rhs, ref end_kind) => { rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span) } - ast::TyPatKind::Err(_) => Err(RewriteError::Unknown), + ast::TyPatKind::Or(ref variants) => { + let mut first = true; + let mut s = String::new(); + for variant in variants { + if first { + first = false + } else { + s.push_str(" | "); + } + s.push_str(&variant.rewrite_result(context, shape)?); + } + Ok(s) + } + ast::TyPatKind::Err(_) => Err(RewriteError::Unknown(Arc::new(Backtrace::capture()))), } } } -fn rewrite_bare_fn( - bare_fn: &ast::BareFnTy, +fn rewrite_fn_ptr( + fn_ptr: &ast::FnPtrTy, span: Span, context: &RewriteContext<'_>, shape: Shape, @@ -1093,7 +1043,7 @@ fn rewrite_bare_fn( let mut result = String::with_capacity(128); - if let Some(ref lifetime_str) = rewrite_bound_params(context, shape, &bare_fn.generic_params) { + if let Ok(ref lifetime_str) = rewrite_bound_params(context, shape, &fn_ptr.generic_params) { result.push_str("for<"); // 6 = "for<> ".len(), 4 = "for<". // This doesn't work out so nicely for multiline situation with lots of @@ -1102,10 +1052,10 @@ fn rewrite_bare_fn( result.push_str("> "); } - result.push_str(crate::utils::format_safety(bare_fn.safety)); + result.push_str(crate::utils::format_safety(fn_ptr.safety)); result.push_str(&format_extern( - bare_fn.ext, + fn_ptr.ext, context.config.force_explicit_abi(), )); @@ -1120,9 +1070,9 @@ fn rewrite_bare_fn( }; let rewrite = format_function_type( - bare_fn.decl.inputs.iter(), - &bare_fn.decl.output, - bare_fn.decl.c_variadic(), + fn_ptr.decl.inputs.iter(), + &fn_ptr.decl.output, + fn_ptr.decl.c_variadic(), span, context, func_ty_shape, @@ -1315,7 +1265,7 @@ fn join_bounds_inner( } } -pub(crate) fn opaque_ty(ty: &Option>) -> Option<&ast::GenericBounds> { +pub(crate) fn opaque_ty(ty: &Option>) -> Option<&ast::GenericBounds> { ty.as_ref().and_then(|t| match &t.kind { ast::TyKind::ImplTrait(_, bounds) => Some(bounds), _ => None, @@ -1341,15 +1291,15 @@ pub(crate) fn rewrite_bound_params( context: &RewriteContext<'_>, shape: Shape, generic_params: &[ast::GenericParam], -) -> Option { +) -> Result { let result = generic_params .iter() - .map(|param| param.rewrite(context, shape)) - .collect::>>()? + .map(|param| param.rewrite_result(context, shape)) + .collect::, _>>()? .join(", "); if result.is_empty() { - None + None.unknown_error() } else { - Some(result) + Ok(result) } } diff --git a/src/utils.rs b/src/utils.rs index fcd475b1784..a3b146da6b7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,17 +1,17 @@ use std::borrow::Cow; +use rustc_ast::YieldKind; use rustc_ast::ast::{ self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility, VisibilityKind, }; -use rustc_ast::{YieldKind, ptr}; use rustc_ast_pretty::pprust; use rustc_span::{BytePos, LocalExpnId, Span, Symbol, SyntaxContext, sym, symbol}; use unicode_width::UnicodeWidthStr; use crate::comment::{CharClasses, FullCodeCharKind, LineClasses, filter_normal_code}; use crate::config::{Config, StyleEdition}; -use crate::rewrite::RewriteContext; +use crate::rewrite::{RewriteContext, RewriteError, RewriteErrorExt}; use crate::shape::{Indent, Shape}; #[inline] @@ -149,8 +149,8 @@ pub(crate) fn format_extern(ext: ast::Extern, explicit_abi: bool) -> Cow<'static } #[inline] -// Transform `Vec>` into `Vec<&T>` -pub(crate) fn ptr_vec_to_ref_vec(vec: &[ptr::P]) -> Vec<&T> { +// Transform `Vec>` into `Vec<&T>` +pub(crate) fn ptr_vec_to_ref_vec(vec: &[Box]) -> Vec<&T> { vec.iter().map(|x| &**x).collect::>() } @@ -378,7 +378,7 @@ macro_rules! skip_out_of_file_lines_range_err { macro_rules! skip_out_of_file_lines_range_visitor { ($self:ident, $span:expr) => { if out_of_file_lines_range!($self, $span) { - $self.push_rewrite($span, None); + $self.push_rewrite($span, None.unknown_error()); return; } }; @@ -386,11 +386,11 @@ macro_rules! skip_out_of_file_lines_range_visitor { // Wraps String in an Option. Returns Some when the string adheres to the // Rewrite constraints defined for the Rewrite trait and None otherwise. -pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Option { +pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Result { if filtered_str_fits(&s, max_width, shape) { - Some(s) + Ok(s) } else { - None + None.unknown_error() } } diff --git a/src/vertical.rs b/src/vertical.rs index 21e34d29710..563de2de25f 100644 --- a/src/vertical.rs +++ b/src/vertical.rs @@ -13,7 +13,7 @@ use crate::items::{rewrite_struct_field, rewrite_struct_field_prefix}; use crate::lists::{ ListFormatting, ListItem, Separator, definitive_tactic, itemize_list, write_list, }; -use crate::rewrite::{Rewrite, RewriteContext, RewriteResult}; +use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult}; use crate::shape::{Indent, Shape}; use crate::source_map::SpanUtils; use crate::spanned::Spanned; @@ -114,7 +114,7 @@ pub(crate) fn rewrite_with_alignment( shape: Shape, span: Span, one_line_width: usize, -) -> Option { +) -> Result { let (spaces, group_index) = if context.config.struct_field_align_threshold() > 0 { group_aligned_items(context, fields) } else { @@ -172,11 +172,11 @@ pub(crate) fn rewrite_with_alignment( force_separator, )?; if rest.is_empty() { - Some(result + spaces) + Ok(result + spaces) } else { let rest_span = mk_sp(init_last_pos, span.hi()); let rest_str = rewrite_with_alignment(rest, context, shape, rest_span, one_line_width)?; - Some(format!( + Ok(format!( "{}{}\n{}{}", result, spaces, @@ -211,9 +211,11 @@ fn rewrite_aligned_items_inner( offset: Indent, one_line_width: usize, force_trailing_separator: bool, -) -> Option { +) -> Result { // 1 = "," - let item_shape = Shape::indented(offset, context.config).sub_width_opt(1)?; + let item_shape = Shape::indented(offset, context.config) + .sub_width_opt(1) + .unknown_error()?; let (mut field_prefix_max_width, field_prefix_min_width) = struct_field_prefix_max_min_width(context, fields, item_shape); let max_diff = field_prefix_max_width.saturating_sub(field_prefix_min_width); @@ -266,7 +268,7 @@ fn rewrite_aligned_items_inner( .tactic(tactic) .trailing_separator(separator_tactic) .preserve_newline(true); - write_list(&items, &fmt).ok() + write_list(&items, &fmt) } /// Returns the index in `fields` up to which a field belongs to the current group. diff --git a/src/visitor.rs b/src/visitor.rs index d7b1178a4e0..d1ecf9db936 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -17,7 +17,7 @@ use crate::items::{ use crate::macros::{MacroPosition, macro_style, rewrite_macro, rewrite_macro_def}; use crate::modules::Module; use crate::parse::session::ParseSess; -use crate::rewrite::{Rewrite, RewriteContext}; +use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt}; use crate::shape::{Indent, Shape}; use crate::skip::{SkipContext, is_skip_attr}; use crate::source_map::{LineRangeUtils, SpanUtils}; @@ -160,7 +160,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ); } else { let shape = self.shape(); - let rewrite = self.with_context(|ctx| stmt.rewrite(ctx, shape)); + let rewrite = self.with_context(|ctx| stmt.rewrite_result(ctx, shape)); self.push_rewrite(stmt.span(), rewrite) } } @@ -408,7 +408,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { if let Some((fn_str, fn_brace_style)) = rewrite { self.format_missing_with_indent(source!(self, s).lo()); - if let Some(rw) = self.single_line_fn(&fn_str, block, inner_attrs) { + if let Ok(rw) = self.single_line_fn(&fn_str, block, inner_attrs) { self.push_str(&rw); self.last_pos = s.hi(); return; @@ -490,13 +490,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ast::ItemKind::Impl(ref iimpl) => { let block_indent = self.block_indent; let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent)); - self.push_rewrite(item.span, rw.ok()); + self.push_rewrite(item.span, rw); } ast::ItemKind::Trait(ref trait_kind) => { let block_indent = self.block_indent; let rw = self.with_context(|ctx| format_trait(ctx, item, trait_kind, block_indent)); - self.push_rewrite(item.span, rw.ok()); + self.push_rewrite(item.span, rw); } ast::ItemKind::TraitAlias(ident, ref generics, ref generic_bounds) => { let shape = Shape::indented(self.block_indent, self.config); @@ -508,7 +508,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { generic_bounds, shape, ); - self.push_rewrite(item.span, rw.ok()); + self.push_rewrite(item.span, rw); } ast::ItemKind::ExternCrate(..) => { let rw = rewrite_extern_crate(&self.get_context(), item, self.shape()); @@ -517,12 +517,12 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } else { mk_sp(attrs[0].span.lo(), item.span.hi()) }; - self.push_rewrite(span, rw.ok()); + self.push_rewrite(span, rw); } ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => { self.visit_struct(&StructParts::from_item(item)); } - ast::ItemKind::Enum(ident, ref def, ref generics) => { + ast::ItemKind::Enum(ident, ref generics, ref def) => { self.format_missing_with_indent(source!(self, item.span).lo()); self.visit_enum(ident, &item.vis, def, generics, item.span); self.last_pos = source!(self, item.span).hi(); @@ -566,9 +566,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ) } else { let indent = self.block_indent; - let rewrite = self - .rewrite_required_fn(indent, ident, sig, &item.vis, generics, item.span) - .ok(); + let rewrite = self.rewrite_required_fn( + indent, ident, sig, &item.vis, generics, item.span, + ); self.push_rewrite(item.span, rewrite); } } @@ -577,7 +577,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.visit_ty_alias_kind(ty_alias, &item.vis, Item, item.span); } ast::ItemKind::GlobalAsm(..) => { - let snippet = Some(self.snippet(item.span).to_owned()); + let snippet = Ok(self.snippet(item.span).to_owned()); self.push_rewrite(item.span, snippet); } ast::ItemKind::MacroDef(ident, ref def) => { @@ -589,14 +589,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ident, &item.vis, item.span, - ) - .ok(); + ); self.push_rewrite(item.span, rewrite); } ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => { // TODO: rewrite delegation items once syntax is established. // For now, leave the contents of the Span unformatted. - self.push_rewrite(item.span, None) + self.push_rewrite(item.span, None.unknown_error()) } }; } @@ -617,8 +616,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.block_indent, visitor_kind, span, - ) - .ok(); + ); self.push_rewrite(span, rewrite); } @@ -669,9 +667,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ); } else { let indent = self.block_indent; - let rewrite = self - .rewrite_required_fn(indent, fn_kind.ident, sig, &ai.vis, generics, ai.span) - .ok(); + let rewrite = self.rewrite_required_fn( + indent, + fn_kind.ident, + sig, + &ai.vis, + generics, + ai.span, + ); self.push_rewrite(ai.span, rewrite); } } @@ -698,7 +701,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, ctx, shape, pos).ok()); + let rewrite = self.with_context(|ctx| rewrite_macro(mac, ctx, shape, pos)); // 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) ;`) @@ -729,8 +732,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } #[allow(clippy::needless_pass_by_value)] - fn push_rewrite_inner(&mut self, span: Span, rewrite: Option) { - if let Some(ref s) = rewrite { + fn push_rewrite_inner(&mut self, span: Span, rewrite: Result) { + if let Ok(ref s) = rewrite { self.push_str(s); } else { let snippet = self.snippet(span); @@ -739,7 +742,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.last_pos = source!(self, span).hi(); } - pub(crate) fn push_rewrite(&mut self, span: Span, rewrite: Option) { + pub(crate) fn push_rewrite(&mut self, span: Span, rewrite: Result) { self.format_missing_with_indent(source!(self, span).lo()); self.push_rewrite_inner(span, rewrite); } @@ -762,7 +765,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { // or it can be on the same line as the last attribute. // So here we need to take a minimum between the two. let lo = std::cmp::min(attrs_end + 1, first_line); - self.push_rewrite_inner(item_span, None); + self.push_rewrite_inner(item_span, None.unknown_error()); let hi = self.line_number + 1; self.skipped_range.borrow_mut().push((lo, hi)); } @@ -861,7 +864,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { return false; } - let rewrite = attrs.rewrite(&self.get_context(), self.shape()); + let rewrite = attrs.rewrite_result(&self.get_context(), self.shape()); let span = mk_sp(attrs[0].span.lo(), attrs[attrs.len() - 1].span.hi()); self.push_rewrite(span, rewrite); @@ -875,7 +878,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { !is_skip_attr(segments) } - fn walk_mod_items(&mut self, items: &[rustc_ast::ptr::P]) { + fn walk_mod_items(&mut self, items: &[Box]) { self.visit_items_with_reordering(&ptr_vec_to_ref_vec(items)); } @@ -943,7 +946,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); self.push_str(&ident_str); - if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind { + if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind { let ast::ModSpans { inner_span, inject_use_span: _, diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index a9f58b9328e..4a9399377d1 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -185,10 +185,11 @@ fn dont_emit_ICE() { "tests/target/issue-6105.rs", ]; + let panic_re = regex::Regex::new("thread.*panicked").unwrap(); for file in files { let args = [file]; let (_stdout, stderr) = rustfmt(&args); - assert!(!stderr.contains("thread 'main' panicked")); + assert!(!panic_re.is_match(&stderr)); } } diff --git a/tests/source/frontmatter_compact.rs b/tests/source/frontmatter_compact.rs new file mode 100644 index 00000000000..21d4c6f4b61 --- /dev/null +++ b/tests/source/frontmatter_compact.rs @@ -0,0 +1,8 @@ +#!/usr/bin/env cargo +---identifier +[dependencies] +regex = "1" +--- +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/source/frontmatter_escaped.rs b/tests/source/frontmatter_escaped.rs new file mode 100644 index 00000000000..0d026377566 --- /dev/null +++ b/tests/source/frontmatter_escaped.rs @@ -0,0 +1,13 @@ +#!/usr/bin/env cargo +------------ +package.description = """ +Header +----- + +Body +""" +------------ + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/source/frontmatter_spaced.rs b/tests/source/frontmatter_spaced.rs new file mode 100644 index 00000000000..ee0bb81705c --- /dev/null +++ b/tests/source/frontmatter_spaced.rs @@ -0,0 +1,16 @@ +#!/usr/bin/env cargo + + +--- identifier +[dependencies] +regex = "1" + +--- + + + + + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/source/html_extractor.rs b/tests/source/html_extractor.rs new file mode 100644 index 00000000000..37dd23b0cc6 --- /dev/null +++ b/tests/source/html_extractor.rs @@ -0,0 +1,6 @@ +pub fn main() { + html_extractor::html! { +

"test" +

+ } +} diff --git a/tests/source/html_extractor_10.rs b/tests/source/html_extractor_10.rs new file mode 100644 index 00000000000..cc76c52f2d6 --- /dev/null +++ b/tests/source/html_extractor_10.rs @@ -0,0 +1,12 @@ +pub fn main() { + html_extractor::html!( +
+let value = if html_handler.test() { +
+ } + => + + value; +
+ ); +} diff --git a/tests/source/html_extractor_11.rs b/tests/source/html_extractor_11.rs new file mode 100644 index 00000000000..b59534e7531 --- /dev/null +++ b/tests/source/html_extractor_11.rs @@ -0,0 +1,14 @@ +pub fn main() { + html_extractor::html!( +
+let value = if html_handler.test() { +
+ } + => + + value else { +
+ } => value; +
+ ); +} diff --git a/tests/source/html_extractor_12.rs b/tests/source/html_extractor_12.rs new file mode 100644 index 00000000000..a16ce33f3ac --- /dev/null +++ b/tests/source/html_extractor_12.rs @@ -0,0 +1,12 @@ +pub fn main() { + html_extractor::html!( +
+let value = while html_handler.test() { +
+ } + => + + value; +
+ ); +} diff --git a/tests/source/html_extractor_13.rs b/tests/source/html_extractor_13.rs new file mode 100644 index 00000000000..836736b86c7 --- /dev/null +++ b/tests/source/html_extractor_13.rs @@ -0,0 +1,12 @@ +pub fn main() { + html_extractor::html! { +
+
+ let + value + = + html_handler.next_any_child(); +
+
+ }; +} diff --git a/tests/source/html_extractor_14.rs b/tests/source/html_extractor_14.rs new file mode 100644 index 00000000000..f2781fabc75 --- /dev/null +++ b/tests/source/html_extractor_14.rs @@ -0,0 +1,13 @@ +pub fn main() { + html_extractor::html! { +

+let location_or_additional_info = if html_handler.peek().is_some() { +let location_or_additional_info = html_handler.next_any_child(); +

_ +} => location_or_additional_info else { +

_ +} => (); +
+
+ }; +} diff --git a/tests/source/html_extractor_2.rs b/tests/source/html_extractor_2.rs new file mode 100644 index 00000000000..5830ae31750 --- /dev/null +++ b/tests/source/html_extractor_2.rs @@ -0,0 +1,11 @@ +pub fn main() { + html_extractor::html! { + lecturers + +

+ + _ + +

+ }; +} diff --git a/tests/source/html_extractor_3.rs b/tests/source/html_extractor_3.rs new file mode 100644 index 00000000000..664ca38ac77 --- /dev/null +++ b/tests/source/html_extractor_3.rs @@ -0,0 +1,19 @@ +pub fn main() { + html_extractor::html!( + + + + + _ + ); +} diff --git a/tests/source/html_extractor_4.rs b/tests/source/html_extractor_4.rs new file mode 100644 index 00000000000..16fc6760d1c --- /dev/null +++ b/tests/source/html_extractor_4.rs @@ -0,0 +1,6 @@ +// rustfmt-format_strings: true +pub fn main() { + html_extractor::html!( + "Archiv" + ); +} diff --git a/tests/source/html_extractor_9.rs b/tests/source/html_extractor_9.rs new file mode 100644 index 00000000000..716662d2e9b --- /dev/null +++ b/tests/source/html_extractor_9.rs @@ -0,0 +1,12 @@ +pub fn main() { + html_extractor::html!( +

+let value = if html_handler { +
+ } + => + + value; +
+ ); +} diff --git a/tests/source/html_extractor_extern.rs b/tests/source/html_extractor_extern.rs new file mode 100644 index 00000000000..e6e70c4d4d0 --- /dev/null +++ b/tests/source/html_extractor_extern.rs @@ -0,0 +1,12 @@ +pub fn main() { + html_extractor::html! { +
+
+ extern { + + println!("hi"); + } +
+
+ }; +} diff --git a/tests/source/html_extractor_use.rs b/tests/source/html_extractor_use.rs new file mode 100644 index 00000000000..5c85b0dae43 --- /dev/null +++ b/tests/source/html_extractor_use.rs @@ -0,0 +1,11 @@ +pub fn main() { + html_extractor::html! { +
+
+ use + parse_stuff(html_handler) + ; +
+
+ }; +} diff --git a/tests/source/issue-6202/long_pat.rs b/tests/source/issue-6202/long_pat.rs index a7f47f32cb2..59aa4090be5 100644 --- a/tests/source/issue-6202/long_pat.rs +++ b/tests/source/issue-6202/long_pat.rs @@ -1,6 +1,7 @@ -// max_width = 120 -// error_on_line_overflow = true -// style_edition = "2027" +// rustfmt-max_width: 120 +// rustfmt-error_on_line_overflow: true +// rustfmt-edition: 2024 +// rustfmt-style_edition: 2027 impl EarlyLintPass for NeedlessContinue { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { diff --git a/tests/source/let_chains.rs b/tests/source/let_chains.rs index 0c4d8aa85ea..fc2a9310569 100644 --- a/tests/source/let_chains.rs +++ b/tests/source/let_chains.rs @@ -1,3 +1,5 @@ +// rustfmt-edition: 2024 + fn main() { if let x = x && x {} diff --git a/tests/source/negative-impl.rs b/tests/source/negative-impl.rs index da242d4f3dc..e8f9508e656 100644 --- a/tests/source/negative-impl.rs +++ b/tests/source/negative-impl.rs @@ -1,7 +1,3 @@ impl ! Display for JoinHandle { } -impl ! Box < JoinHandle > { } - impl ! std :: fmt :: Display for JoinHandle < T : std :: future :: Future + std :: marker :: Send + std :: marker :: Sync > { } - -impl ! JoinHandle < T : std :: future :: Future < Output > + std :: marker :: Send + std :: marker :: Sync + 'static > + 'static { } diff --git a/tests/source/pin_sugar.rs b/tests/source/pin_sugar.rs index 370dfbc196a..e5b47339b92 100644 --- a/tests/source/pin_sugar.rs +++ b/tests/source/pin_sugar.rs @@ -18,3 +18,13 @@ impl Foo { mut self) {} fn i(&pin mut self) {} } + +fn borrows() { + let mut foo = 0_i32; + let x: Pin<&mut _> = & pin + mut foo; + + let x: Pin<&_> = & + pin const + foo; +} diff --git a/tests/source/type.rs b/tests/source/type.rs index 7a232f85198..213fad7cb16 100644 --- a/tests/source/type.rs +++ b/tests/source/type.rs @@ -142,18 +142,18 @@ type MyFn = fn(a: SomeLongComplexType, b: SomeOtherLongComplexType,) -> Box() -> i32 { ::CONST } +const fn not_quite_const() -> i32 { ::CONST } -impl ~ const T {} +impl const T for U {} -fn apit(_: impl ~ const T) {} +fn apit(_: impl [ const ] T) {} -fn rpit() -> impl ~ const T { S } +fn rpit() -> impl [ const] T { S } pub struct Foo(T); -impl Foo { +impl Foo { fn new(t: T) -> Self { Self(t) } diff --git a/tests/target/frontmatter_compact.rs b/tests/target/frontmatter_compact.rs new file mode 100644 index 00000000000..21d4c6f4b61 --- /dev/null +++ b/tests/target/frontmatter_compact.rs @@ -0,0 +1,8 @@ +#!/usr/bin/env cargo +---identifier +[dependencies] +regex = "1" +--- +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/target/frontmatter_escaped.rs b/tests/target/frontmatter_escaped.rs new file mode 100644 index 00000000000..0d026377566 --- /dev/null +++ b/tests/target/frontmatter_escaped.rs @@ -0,0 +1,13 @@ +#!/usr/bin/env cargo +------------ +package.description = """ +Header +----- + +Body +""" +------------ + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/target/frontmatter_spaced.rs b/tests/target/frontmatter_spaced.rs new file mode 100644 index 00000000000..ee0bb81705c --- /dev/null +++ b/tests/target/frontmatter_spaced.rs @@ -0,0 +1,16 @@ +#!/usr/bin/env cargo + + +--- identifier +[dependencies] +regex = "1" + +--- + + + + + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/target/html_extractor.rs b/tests/target/html_extractor.rs new file mode 100644 index 00000000000..a203107dfb6 --- /dev/null +++ b/tests/target/html_extractor.rs @@ -0,0 +1,7 @@ +pub fn main() { + html_extractor::html! { +

+ "test" +

+ } +} diff --git a/tests/target/html_extractor_10.rs b/tests/target/html_extractor_10.rs new file mode 100644 index 00000000000..061b7555e9b --- /dev/null +++ b/tests/target/html_extractor_10.rs @@ -0,0 +1,12 @@ +pub fn main() { + html_extractor::html! { +
+
+ let value = if html_handler.test() { +
+
+ } => value; +
+
+ }; +} diff --git a/tests/target/html_extractor_11.rs b/tests/target/html_extractor_11.rs new file mode 100644 index 00000000000..07d6a079169 --- /dev/null +++ b/tests/target/html_extractor_11.rs @@ -0,0 +1,15 @@ +pub fn main() { + html_extractor::html! { +
+
+ let value = if html_handler.test() { +
+
+ } => value else { +
+
+ } => value; +
+
+ }; +} diff --git a/tests/target/html_extractor_12.rs b/tests/target/html_extractor_12.rs new file mode 100644 index 00000000000..bf79947e65a --- /dev/null +++ b/tests/target/html_extractor_12.rs @@ -0,0 +1,12 @@ +pub fn main() { + html_extractor::html! { +
+
+ let value = while html_handler.test() { +
+
+ } => value; +
+
+ }; +} diff --git a/tests/target/html_extractor_13.rs b/tests/target/html_extractor_13.rs new file mode 100644 index 00000000000..b1a1980e81d --- /dev/null +++ b/tests/target/html_extractor_13.rs @@ -0,0 +1,9 @@ +pub fn main() { + html_extractor::html! { +
+
+ let value = html_handler.next_any_child(); +
+
+ }; +} diff --git a/tests/target/html_extractor_14.rs b/tests/target/html_extractor_14.rs new file mode 100644 index 00000000000..b18201def84 --- /dev/null +++ b/tests/target/html_extractor_14.rs @@ -0,0 +1,13 @@ +pub fn main() { + html_extractor::html! { +

+ let location_or_additional_info = if html_handler.peek().is_some() { + let location_or_additional_info = html_handler.next_any_child(); +

+ } => location_or_additional_info else { +

+ } => (); +
+
+ }; +} diff --git a/tests/target/html_extractor_2.rs b/tests/target/html_extractor_2.rs new file mode 100644 index 00000000000..2379d62111b --- /dev/null +++ b/tests/target/html_extractor_2.rs @@ -0,0 +1,7 @@ +pub fn main() { + html_extractor::html! { + lecturers +

+

+ }; +} diff --git a/tests/target/html_extractor_3.rs b/tests/target/html_extractor_3.rs new file mode 100644 index 00000000000..2732573a148 --- /dev/null +++ b/tests/target/html_extractor_3.rs @@ -0,0 +1,5 @@ +pub fn main() { + html_extractor::html! { + + }; +} diff --git a/tests/target/html_extractor_4.rs b/tests/target/html_extractor_4.rs new file mode 100644 index 00000000000..76b8ebd25db --- /dev/null +++ b/tests/target/html_extractor_4.rs @@ -0,0 +1,13 @@ +// rustfmt-format_strings: true +pub fn main() { + html_extractor::html! { + + "Archiv" + + }; +} diff --git a/tests/target/html_extractor_5.rs b/tests/target/html_extractor_5.rs new file mode 100644 index 00000000000..c7a402156ca --- /dev/null +++ b/tests/target/html_extractor_5.rs @@ -0,0 +1,14 @@ +// rustfmt-format_strings: true +pub fn main() { + html_extractor::html! { +