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("");
+ result.push_str(tag.as_str());
+ 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("");
+ if let Some(tag) = tag {
+ result.push_str(
+ &tag.rewrite_result(context, Shape::indented(*indent, context.config))
+ .unwrap(),
+ );
+ }
+ 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::
_
+} => ();
+
+
+ };
+}
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! {
+
+ -
+
+ };
+}
diff --git a/tests/target/html_extractor_6.rs b/tests/target/html_extractor_6.rs
new file mode 100644
index 00000000000..67400026d92
--- /dev/null
+++ b/tests/target/html_extractor_6.rs
@@ -0,0 +1,13 @@
+// rustfmt-format_strings: true
+pub fn main() {
+ html_extractor::html! {
+
+ "verylongsttringthatshouldbesplitupbecauseitissolongverylongsttringthatshouldbesplitupbecauseitissolongverylongsttringthatshouldbesplitupbecauseitissolong"
+
+
+
+
+ "Hier"
+
+ };
+}
diff --git a/tests/target/html_extractor_7.rs b/tests/target/html_extractor_7.rs
new file mode 100644
index 00000000000..abfda24f731
--- /dev/null
+++ b/tests/target/html_extractor_7.rs
@@ -0,0 +1,5 @@
+pub fn main() {
+ html_extractor::html! {
+
+ };
+}
diff --git a/tests/target/html_extractor_8.rs b/tests/target/html_extractor_8.rs
new file mode 100644
index 00000000000..90809fcd1c1
--- /dev/null
+++ b/tests/target/html_extractor_8.rs
@@ -0,0 +1,13 @@
+// TODO FIXME ignored rustfmt-error_on_unformatted: true
+pub fn main() {
+ {
+ html_extractor::html!(
+ // commentmatters
+
+
+ module_idmodule_name
+ lecturer
+ |
+ );
+ }
+}
diff --git a/tests/target/html_extractor_9.rs b/tests/target/html_extractor_9.rs
new file mode 100644
index 00000000000..9a9ea79cb41
--- /dev/null
+++ b/tests/target/html_extractor_9.rs
@@ -0,0 +1,12 @@
+pub fn main() {
+ html_extractor::html! {
+
+
+ let value = if html_handler {
+
+
+ } => value;
+
+
+ };
+}
diff --git a/tests/target/html_extractor_extern.rs b/tests/target/html_extractor_extern.rs
new file mode 100644
index 00000000000..036f8b8559d
--- /dev/null
+++ b/tests/target/html_extractor_extern.rs
@@ -0,0 +1,11 @@
+pub fn main() {
+ html_extractor::html! {
+
+
+ extern {
+ println!("hi");
+ }
+
+
+ };
+}
diff --git a/tests/target/html_extractor_use.rs b/tests/target/html_extractor_use.rs
new file mode 100644
index 00000000000..858648f80e3
--- /dev/null
+++ b/tests/target/html_extractor_use.rs
@@ -0,0 +1,9 @@
+pub fn main() {
+ html_extractor::html! {
+
+
+ use parse_stuff(html_handler);
+
+
+ };
+}
diff --git a/tests/target/issue-6202/long_pat.rs b/tests/target/issue-6202/long_pat.rs
index fef118a9da2..9e4accb29df 100644
--- a/tests/target/issue-6202/long_pat.rs
+++ b/tests/target/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/target/issue_5542.rs b/tests/target/issue_5542.rs
deleted file mode 100644
index 730bb7b681a..00000000000
--- a/tests/target/issue_5542.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(dyn_star)]
-#![allow(incomplete_features)]
-
-use core::fmt::Debug;
-
-fn main() {
- let i = 42;
- let dyn_i = i as dyn* Debug;
- dbg!(dyn_i);
-}
diff --git a/tests/target/let_chains.rs b/tests/target/let_chains.rs
index 204937b4cac..4fd6048d914 100644
--- a/tests/target/let_chains.rs
+++ b/tests/target/let_chains.rs
@@ -1,3 +1,5 @@
+// rustfmt-edition: 2024
+
fn main() {
if let x = x
&& x
diff --git a/tests/target/negative-impl.rs b/tests/target/negative-impl.rs
index 16ce7e26a99..bb53048dbc6 100644
--- a/tests/target/negative-impl.rs
+++ b/tests/target/negative-impl.rs
@@ -1,14 +1,6 @@
impl !Display for JoinHandle {}
-impl !Box {}
-
impl !std::fmt::Display
for JoinHandle
{
}
-
-impl
- !JoinHandle + std::marker::Send + std::marker::Sync + 'static>
- + 'static
-{
-}
diff --git a/tests/target/pin_sugar.rs b/tests/target/pin_sugar.rs
index 7d04efb1b32..09ad23a5807 100644
--- a/tests/target/pin_sugar.rs
+++ b/tests/target/pin_sugar.rs
@@ -16,3 +16,10 @@ impl Foo {
fn h<'a>(&'a pin 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/target/type.rs b/tests/target/type.rs
index 325adb52f3f..93479f8b484 100644
--- a/tests/target/type.rs
+++ b/tests/target/type.rs
@@ -147,22 +147,22 @@ type MyFn = fn(
// Const bound
-trait T: ~const Super {}
+trait T: [const] Super {}
-const fn not_quite_const() -> i32 {
+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 {
+fn rpit() -> impl [const] T {
S
}
pub struct Foo(T);
-impl Foo {
+impl Foo {
fn new(t: T) -> Self {
Self(t)
}