diff --git a/CHANGELOG.md b/CHANGELOG.md index 89e90fb17dd..97b73c71146 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -238,7 +238,7 @@ ### Added -- New configuration option (`skip_macro_invocations`)[https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations] [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726) +- New configuration option [`skip_macro_invocations`](https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations) [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726) ### Misc diff --git a/rust-toolchain b/rust-toolchain index 25e3961d32a..d04c524861a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-06-13" +channel = "nightly-2024-06-25" components = ["llvm-tools", "rustc-dev"] diff --git a/src/config/mod.rs b/src/config/mod.rs index 9484b2e5829..eb92b8f6eeb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -256,7 +256,7 @@ impl Config { /// one. pub(super) fn from_resolved_toml_path(dir: &Path) -> Result<(Config, Option), Error> { /// Try to find a project file in the given directory and its parents. - /// Returns the path of a the nearest project file if one exists, + /// Returns the path of the nearest project file if one exists, /// or `None` if no project file was found. fn resolve_project_file(dir: &Path) -> Result, Error> { let mut current = if dir.is_relative() { diff --git a/src/expr.rs b/src/expr.rs index 8266f95fd70..8b63c1b5f1d 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1860,7 +1860,11 @@ fn rewrite_let( // TODO(ytmimi) comments could appear between `let` and the `pat` // 4 = "let ".len() - let pat_shape = shape.offset_left(4)?; + let mut pat_shape = shape.offset_left(4)?; + if context.config.version() == Version::Two { + // 2 to account for the length of " =" + pat_shape = pat_shape.sub_width(2)?; + } let pat_str = pat.rewrite(context, pat_shape)?; result.push_str(&pat_str); diff --git a/src/items.rs b/src/items.rs index c8ea104e9d6..eb11604b277 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1994,7 +1994,6 @@ fn rewrite_static( static_parts: &StaticParts<'_>, offset: Indent, ) -> Option { - println!("rewriting static"); let colon = colon_spaces(context.config); let mut prefix = format!( "{}{}{}{} {}{}{}", diff --git a/src/overflow.rs b/src/overflow.rs index c44f3788d97..a1de71a35be 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -83,6 +83,7 @@ pub(crate) enum OverflowableItem<'a> { TuplePatField(&'a TuplePatField<'a>), Ty(&'a ast::Ty), Pat(&'a ast::Pat), + PreciseCapturingArg(&'a ast::PreciseCapturingArg), } impl<'a> Rewrite for OverflowableItem<'a> { @@ -123,6 +124,7 @@ impl<'a> OverflowableItem<'a> { OverflowableItem::TuplePatField(pat) => f(*pat), OverflowableItem::Ty(ty) => f(*ty), OverflowableItem::Pat(pat) => f(*pat), + OverflowableItem::PreciseCapturingArg(arg) => f(*arg), } } @@ -137,6 +139,9 @@ impl<'a> OverflowableItem<'a> { matches!(meta_item.kind, ast::MetaItemKind::Word) } }, + // FIXME: Why don't we consider `SegmentParam` to be simple? + // FIXME: If we also fix `SegmentParam`, then we should apply the same + // heuristic to `PreciseCapturingArg`. _ => false, } } @@ -244,7 +249,15 @@ macro_rules! impl_into_overflowable_item_for_rustfmt_types { } } -impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty, Pat); +impl_into_overflowable_item_for_ast_node!( + Expr, + GenericParam, + NestedMetaItem, + FieldDef, + Ty, + Pat, + PreciseCapturingArg +); impl_into_overflowable_item_for_rustfmt_types!([MacroArg], [SegmentParam, TuplePatField]); pub(crate) fn into_overflowable_list<'a, T>( diff --git a/src/parse/macros/cfg_if.rs b/src/parse/macros/cfg_if.rs index 5fc988e4319..b91d203d531 100644 --- a/src/parse/macros/cfg_if.rs +++ b/src/parse/macros/cfg_if.rs @@ -67,7 +67,7 @@ fn parse_cfg_if_inner<'a>( Ok(None) => continue, Err(err) => { err.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); return Err( "Expected item inside cfg_if block, but failed to parse it as an item", ); diff --git a/src/parse/macros/lazy_static.rs b/src/parse/macros/lazy_static.rs index badd9569950..7baac247e22 100644 --- a/src/parse/macros/lazy_static.rs +++ b/src/parse/macros/lazy_static.rs @@ -16,8 +16,8 @@ pub(crate) fn parse_lazy_static( ($method:ident $(,)* $($arg:expr),* $(,)*) => { match parser.$method($($arg,)*) { Ok(val) => { - if parser.psess.dcx.has_errors().is_some() { - parser.psess.dcx.reset_err_count(); + if parser.psess.dcx().has_errors().is_some() { + parser.psess.dcx().reset_err_count(); return None; } else { val @@ -25,13 +25,12 @@ pub(crate) fn parse_lazy_static( } Err(err) => { err.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); return None; } } } } - while parser.token.kind != TokenKind::Eof { // Parse a `lazy_static!` item. let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No); diff --git a/src/parse/macros/mod.rs b/src/parse/macros/mod.rs index cbcc0b2d636..60c827fd03b 100644 --- a/src/parse/macros/mod.rs +++ b/src/parse/macros/mod.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind}; +use rustc_ast::token::{Delimiter, NonterminalKind, NtExprKind::*, NtPatKind::*, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ast, ptr}; use rustc_parse::parser::{ForceCollect, Parser, Recovery}; @@ -29,8 +29,8 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) { match $try_parse(&mut cloned_parser) { Ok(x) => { - if parser.psess.dcx.has_errors().is_some() { - parser.psess.dcx.reset_err_count(); + if parser.psess.dcx().has_errors().is_some() { + parser.psess.dcx().reset_err_count(); } else { // Parsing succeeded. *parser = cloned_parser; @@ -39,7 +39,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { } Err(e) => { e.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); } } } @@ -48,7 +48,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { parse_macro_arg!( Expr, - NonterminalKind::Expr, + NonterminalKind::Expr(Expr), |parser: &mut Parser<'b>| parser.parse_expr(), |x: ptr::P| Some(x) ); @@ -60,7 +60,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { ); parse_macro_arg!( Pat, - NonterminalKind::PatParam { inferred: false }, + NonterminalKind::Pat(PatParam { inferred: false }), |parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None), |x: ptr::P| Some(x) ); diff --git a/src/parse/session.rs b/src/parse/session.rs index 5ed2a8dbebb..05cf467167c 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -210,7 +210,9 @@ impl ParseSess { rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false, ); - self.raw_psess.dcx.make_silent(fallback_bundle, None, false); + self.raw_psess + .dcx() + .make_silent(fallback_bundle, None, false); } pub(crate) fn span_to_filename(&self, span: Span) -> FileName { @@ -286,11 +288,11 @@ impl ParseSess { } pub(super) fn has_errors(&self) -> bool { - self.raw_psess.dcx.has_errors().is_some() + self.raw_psess.dcx().has_errors().is_some() } pub(super) fn reset_errors(&self) { - self.raw_psess.dcx.reset_err_count(); + self.raw_psess.dcx().reset_err_count(); } } diff --git a/src/spanned.rs b/src/spanned.rs index 4aaf7fdb27f..1ee691b4ade 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -181,6 +181,7 @@ impl Spanned for ast::GenericBound { match *self { ast::GenericBound::Trait(ref ptr, _) => ptr.span, ast::GenericBound::Outlives(ref l) => l.ident.span, + ast::GenericBound::Use(_, span) => span, } } } @@ -202,3 +203,12 @@ impl Spanned for ast::NestedMetaItem { self.span() } } + +impl Spanned for ast::PreciseCapturingArg { + fn span(&self) -> Span { + match self { + ast::PreciseCapturingArg::Lifetime(lt) => lt.ident.span, + ast::PreciseCapturingArg::Arg(path, _) => path.span, + } + } +} diff --git a/src/types.rs b/src/types.rs index fd480393584..c0bf9482b11 100644 --- a/src/types.rs +++ b/src/types.rs @@ -177,6 +177,17 @@ impl<'a> Rewrite for SegmentParam<'a> { } } +impl Rewrite for ast::PreciseCapturingArg { + fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { + match self { + ast::PreciseCapturingArg::Lifetime(lt) => lt.rewrite(context, shape), + ast::PreciseCapturingArg::Arg(p, _) => { + rewrite_path(context, PathContext::Type, &None, p, shape) + } + } + } +} + impl Rewrite for ast::AssocItemConstraint { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { use ast::AssocItemConstraintKind::{Bound, Equality}; @@ -564,6 +575,9 @@ impl Rewrite for ast::GenericBound { .map(|s| format!("{constness}{asyncness}{polarity}{s}")) .map(|s| if has_paren { format!("({})", s) } else { s }) } + ast::GenericBound::Use(ref args, span) => { + overflow::rewrite_with_angle_brackets(context, "use", args.iter(), shape, span) + } ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape), } } @@ -847,11 +861,7 @@ impl Rewrite for ast::Ty { rewrite_macro(mac, None, context, shape, MacroPosition::Expression) } ast::TyKind::ImplicitSelf => Some(String::from("")), - ast::TyKind::ImplTrait(_, ref it, ref captures) => { - // FIXME(precise_capturing): Implement formatting. - if captures.is_some() { - return None; - } + ast::TyKind::ImplTrait(_, ref it) => { // Empty trait is not a parser error. if it.is_empty() { return Some("impl".to_owned()); @@ -935,7 +945,7 @@ fn rewrite_bare_fn( fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool { let is_trait = |b: &ast::GenericBound| match b { ast::GenericBound::Outlives(..) => false, - ast::GenericBound::Trait(..) => true, + ast::GenericBound::Trait(..) | ast::GenericBound::Use(..) => true, }; let is_lifetime = |b: &ast::GenericBound| !is_trait(b); let last_trait_index = generic_bounds.iter().rposition(is_trait); @@ -969,7 +979,8 @@ fn join_bounds_inner( let generic_bounds_in_order = is_generic_bounds_in_order(items); let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b { ast::GenericBound::Outlives(..) => true, - ast::GenericBound::Trait(..) => last_line_extendable(s), + // We treat `use<>` like a trait bound here. + ast::GenericBound::Trait(..) | ast::GenericBound::Use(..) => last_line_extendable(s), }; // Whether a GenericBound item is a PathSegment segment that includes internal array @@ -991,6 +1002,7 @@ fn join_bounds_inner( } } } + ast::GenericBound::Use(args, _) => args.len() > 1, _ => false, }; @@ -1114,8 +1126,7 @@ fn join_bounds_inner( pub(crate) fn opaque_ty(ty: &Option>) -> Option<&ast::GenericBounds> { ty.as_ref().and_then(|t| match &t.kind { - // FIXME(precise_capturing): Implement support here - ast::TyKind::ImplTrait(_, bounds, _) => Some(bounds), + ast::TyKind::ImplTrait(_, bounds) => Some(bounds), _ => None, }) } diff --git a/tests/source/issue-6202/issue_example.rs b/tests/source/issue-6202/issue_example.rs new file mode 100644 index 00000000000..1a3d24699c2 --- /dev/null +++ b/tests/source/issue-6202/issue_example.rs @@ -0,0 +1,13 @@ +// rustfmt-max_width: 120 +// rustfmt-version: Two + +impl EarlyLintPass for NeedlessContinue { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let ExprKind::Loop(body, label, ..) | ExprKind::While(_, body, label) | ExprKind::ForLoop { body, label, .. } = + &expr.kind + && !in_external_macro(cx.sess, expr.span) + { + check_final_block_stmt(cx, body, label, expr.span.ctxt()); + } + } +} \ No newline at end of file diff --git a/tests/source/precise-capturing.rs b/tests/source/precise-capturing.rs new file mode 100644 index 00000000000..b61cceeffe8 --- /dev/null +++ b/tests/source/precise-capturing.rs @@ -0,0 +1,9 @@ +fn hello() -> impl +use<'a> + Sized {} + +fn all_three() -> impl Sized + use<'a> + 'a; + +fn pathological() -> impl use<'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, +'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, +'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, +'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a> + Sized {} diff --git a/tests/target/issue-6202/issue_example.rs b/tests/target/issue-6202/issue_example.rs new file mode 100644 index 00000000000..0c8408324c9 --- /dev/null +++ b/tests/target/issue-6202/issue_example.rs @@ -0,0 +1,14 @@ +// rustfmt-max_width: 120 +// rustfmt-version: Two + +impl EarlyLintPass for NeedlessContinue { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let ExprKind::Loop(body, label, ..) + | ExprKind::While(_, body, label) + | ExprKind::ForLoop { body, label, .. } = &expr.kind + && !in_external_macro(cx.sess, expr.span) + { + check_final_block_stmt(cx, body, label, expr.span.ctxt()); + } + } +} diff --git a/tests/target/precise-capturing.rs b/tests/target/precise-capturing.rs new file mode 100644 index 00000000000..d21374f44c1 --- /dev/null +++ b/tests/target/precise-capturing.rs @@ -0,0 +1,55 @@ +fn hello() -> impl use<'a> + Sized {} + +fn all_three() -> impl Sized + use<'a> + 'a; + +fn pathological() -> impl use< + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, + 'a, +> + Sized { +}