diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index c44f3788d9770..a1de71a35be84 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/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/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index 28911f8af1dfb..1ee691b4ade0e 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -203,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/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index c12f271bc5d2b..c0bf9482b1143 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/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,9 +575,10 @@ 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), - // FIXME(precise_capturing): Should implement formatting before stabilization. - ast::GenericBound::Use(..) => None, } } } @@ -933,9 +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, - // FIXME(precise_capturing): This ordering fn should be reworked. - ast::GenericBound::Use(..) => false, + 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,9 +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), - // FIXME(precise_capturing): This ordering fn should be reworked. - ast::GenericBound::Use(..) => true, + // 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 @@ -993,6 +1002,7 @@ fn join_bounds_inner( } } } + ast::GenericBound::Use(args, _) => args.len() > 1, _ => false, }; diff --git a/src/tools/rustfmt/tests/source/precise-capturing.rs b/src/tools/rustfmt/tests/source/precise-capturing.rs new file mode 100644 index 0000000000000..b61cceeffe89c --- /dev/null +++ b/src/tools/rustfmt/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/src/tools/rustfmt/tests/target/precise-capturing.rs b/src/tools/rustfmt/tests/target/precise-capturing.rs new file mode 100644 index 0000000000000..d21374f44c1ec --- /dev/null +++ b/src/tools/rustfmt/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 { +}