rustfmt
rustfmt copied to clipboard
extremely slow performance with deeply indented bag of stuff
A user reported rustfmt
hanging at https://github.com/dtolnay/cargo-expand/issues/161.
Here's a semi-reduced example:
fn foo() {
{
{
{
pub fn file (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { state . rule (Rule :: file , | state | { state . sequence (| state | { self :: SOI (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { state . sequence (| state | { state . optional (| state | { self :: A (state) . or_else (| state | { self :: B (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: NEWLINE (state) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: A (state) . or_else (| state | { self :: B (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: NEWLINE (state) }) }) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: EOI (state) }) }) }) }
}
}
}
}
That takes about 80s to format on my system.
Here is the original code in full:
# ! [feature (prelude_import)] # [prelude_import] use std :: prelude :: rust_2021 :: * ; # [macro_use] extern crate std ; extern crate pest ; # [macro_use] extern crate pest_derive ; # [grammar = "grm.pest"] pub struct MyParser ; # [allow (non_upper_case_globals)] const _PEST_GRAMMAR_MyParser : & 'static str = "A = { \"A\" }\nB = { \"B\" }\nfile = {\n SOI ~\n (( A | B )? ~ NEWLINE)* ~\n EOI\n}\n\n" ; # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] pub enum Rule { EOI , A , B , file , } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: clone :: Clone for Rule { # [inline] fn clone (& self) -> Rule { * self } } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: marker :: Copy for Rule { } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: fmt :: Debug for Rule { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { match self { Rule :: EOI => :: core :: fmt :: Formatter :: write_str (f , "EOI") , Rule :: A => :: core :: fmt :: Formatter :: write_str (f , "A") , Rule :: B => :: core :: fmt :: Formatter :: write_str (f , "B") , Rule :: file => :: core :: fmt :: Formatter :: write_str (f , "file") , } } } # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: marker :: StructuralEq for Rule { } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: cmp :: Eq for Rule { # [inline] # [doc (hidden)] # [no_coverage] fn assert_receiver_is_total_eq (& self) -> () { } } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: hash :: Hash for Rule { fn hash < __H : :: core :: hash :: Hasher > (& self , state : & mut __H) -> () { let __self_tag = :: core :: intrinsics :: discriminant_value (self) ; :: core :: hash :: Hash :: hash (& __self_tag , state) } } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: cmp :: Ord for Rule { # [inline] fn cmp (& self , other : & Rule) -> :: core :: cmp :: Ordering { let __self_tag = :: core :: intrinsics :: discriminant_value (self) ; let __arg1_tag = :: core :: intrinsics :: discriminant_value (other) ; :: core :: cmp :: Ord :: cmp (& __self_tag , & __arg1_tag) } } # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: marker :: StructuralPartialEq for Rule { } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: cmp :: PartialEq for Rule { # [inline] fn eq (& self , other : & Rule) -> bool { let __self_tag = :: core :: intrinsics :: discriminant_value (self) ; let __arg1_tag = :: core :: intrinsics :: discriminant_value (other) ; __self_tag == __arg1_tag } } # [automatically_derived] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] impl :: core :: cmp :: PartialOrd for Rule { # [inline] fn partial_cmp (& self , other : & Rule) -> :: core :: option :: Option < :: core :: cmp :: Ordering > { let __self_tag = :: core :: intrinsics :: discriminant_value (self) ; let __arg1_tag = :: core :: intrinsics :: discriminant_value (other) ; :: core :: cmp :: PartialOrd :: partial_cmp (& __self_tag , & __arg1_tag) } } # [allow (clippy :: all)] impl :: pest :: Parser < Rule > for MyParser { fn parse < 'i > (rule : Rule , input : & 'i str) -> :: std :: result :: Result < :: pest :: iterators :: Pairs < 'i , Rule > , :: pest :: error :: Error < Rule > > { mod rules { # ! [allow (clippy :: upper_case_acronyms)] pub mod hidden { use super :: super :: Rule ; # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn skip (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { Ok (state) } } pub mod visible { use super :: super :: Rule ; # [inline] # [allow (non_snake_case , unused_variables)] pub fn A (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { state . rule (Rule :: A , | state | { state . match_string ("A") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn B (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { state . rule (Rule :: B , | state | { state . match_string ("B") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn file (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { state . rule (Rule :: file , | state | { state . sequence (| state | { self :: SOI (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { state . sequence (| state | { state . optional (| state | { self :: A (state) . or_else (| state | { self :: B (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: NEWLINE (state) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: A (state) . or_else (| state | { self :: B (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: NEWLINE (state) }) }) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: EOI (state) }) }) }) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn EOI (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { state . rule (Rule :: EOI , | state | state . end_of_input ()) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn SOI (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { state . start_of_input () } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn NEWLINE (state : :: std :: boxed :: Box < :: pest :: ParserState < Rule > >) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < Rule > > > { state . match_string ("\n") . or_else (| state | state . match_string ("\r\n")) . or_else (| state | state . match_string ("\r")) } } pub use self :: visible :: * ; } :: pest :: state (input , | state | { match rule { Rule :: A => rules :: A (state) , Rule :: B => rules :: B (state) , Rule :: file => rules :: file (state) , Rule :: EOI => rules :: EOI (state) , } }) } } fn main () { }
And formatting that code looks like:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[grammar = "grm.pest"]
pub struct MyParser;
#[allow(non_upper_case_globals)]
const _PEST_GRAMMAR_MyParser: &'static str =
"A = { \"A\" }\nB = { \"B\" }\nfile = {\n SOI ~\n (( A | B )? ~ NEWLINE)* ~\n EOI\n}\n\n";
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
pub enum Rule {
EOI,
A,
B,
file,
}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::clone::Clone for Rule {
#[inline]
fn clone(&self) -> Rule {
*self
}
}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::marker::Copy for Rule {}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::fmt::Debug for Rule {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Rule::EOI => ::core::fmt::Formatter::write_str(f, "EOI"),
Rule::A => ::core::fmt::Formatter::write_str(f, "A"),
Rule::B => ::core::fmt::Formatter::write_str(f, "B"),
Rule::file => ::core::fmt::Formatter::write_str(f, "file"),
}
}
}
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::marker::StructuralEq for Rule {}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::cmp::Eq for Rule {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq(&self) -> () {}
}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::hash::Hash for Rule {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let __self_tag = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_tag, state)
}
}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::cmp::Ord for Rule {
#[inline]
fn cmp(&self, other: &Rule) -> ::core::cmp::Ordering {
let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag)
}
}
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::marker::StructuralPartialEq for Rule {}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::cmp::PartialEq for Rule {
#[inline]
fn eq(&self, other: &Rule) -> bool {
let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
__self_tag == __arg1_tag
}
}
#[automatically_derived]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
impl ::core::cmp::PartialOrd for Rule {
#[inline]
fn partial_cmp(&self, other: &Rule) -> ::core::option::Option<::core::cmp::Ordering> {
let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag)
}
}
#[allow(clippy::all)]
impl ::pest::Parser<Rule> for MyParser {
fn parse<'i>(
rule: Rule,
input: &'i str,
) -> ::std::result::Result<::pest::iterators::Pairs<'i, Rule>, ::pest::error::Error<Rule>> {
mod rules {
#![allow(clippy::upper_case_acronyms)]
pub mod hidden {
use super::super::Rule;
#[inline]
#[allow(dead_code, non_snake_case, unused_variables)]
pub fn skip(
state: ::std::boxed::Box<::pest::ParserState<Rule>>,
) -> ::pest::ParseResult<::std::boxed::Box<::pest::ParserState<Rule>>>
{
Ok(state)
}
}
pub mod visible {
use super::super::Rule;
#[inline]
#[allow(non_snake_case, unused_variables)]
pub fn A(
state: ::std::boxed::Box<::pest::ParserState<Rule>>,
) -> ::pest::ParseResult<::std::boxed::Box<::pest::ParserState<Rule>>>
{
state.rule(Rule::A, |state| state.match_string("A"))
}
#[inline]
#[allow(non_snake_case, unused_variables)]
pub fn B(
state: ::std::boxed::Box<::pest::ParserState<Rule>>,
) -> ::pest::ParseResult<::std::boxed::Box<::pest::ParserState<Rule>>>
{
state.rule(Rule::B, |state| state.match_string("B"))
}
#[inline]
#[allow(non_snake_case, unused_variables)]
pub fn file(
state: ::std::boxed::Box<::pest::ParserState<Rule>>,
) -> ::pest::ParseResult<::std::boxed::Box<::pest::ParserState<Rule>>>
{
state.rule(Rule::file,
|state|
{
state.sequence(|state|
{
self::SOI(state).and_then(|state|
{
super::hidden::skip(state)
}).and_then(|state|
{
state.sequence(|state|
{
state.optional(|state|
{
state.sequence(|state|
{
state.optional(|state|
{
self::A(state).or_else(|state| { self::B(state) })
}).and_then(|state|
{
super::hidden::skip(state)
}).and_then(|state| { self::NEWLINE(state) })
}).and_then(|state|
{
state.repeat(|state|
{
state.sequence(|state|
{
super::hidden::skip(state).and_then(|state|
{
state.sequence(|state|
{
state.optional(|state|
{
self::A(state).or_else(|state| { self::B(state) })
}).and_then(|state|
{
super::hidden::skip(state)
}).and_then(|state| { self::NEWLINE(state) })
})
})
})
})
})
})
})
}).and_then(|state|
{
super::hidden::skip(state)
}).and_then(|state| { self::EOI(state) })
})
})
}
#[inline]
#[allow(dead_code, non_snake_case, unused_variables)]
pub fn EOI(
state: ::std::boxed::Box<::pest::ParserState<Rule>>,
) -> ::pest::ParseResult<::std::boxed::Box<::pest::ParserState<Rule>>>
{
state.rule(Rule::EOI, |state| state.end_of_input())
}
#[inline]
#[allow(dead_code, non_snake_case, unused_variables)]
pub fn SOI(
state: ::std::boxed::Box<::pest::ParserState<Rule>>,
) -> ::pest::ParseResult<::std::boxed::Box<::pest::ParserState<Rule>>>
{
state.start_of_input()
}
#[inline]
#[allow(dead_code, non_snake_case, unused_variables)]
pub fn NEWLINE(
state: ::std::boxed::Box<::pest::ParserState<Rule>>,
) -> ::pest::ParseResult<::std::boxed::Box<::pest::ParserState<Rule>>>
{
state
.match_string("\n")
.or_else(|state| state.match_string("\r\n"))
.or_else(|state| state.match_string("\r"))
}
}
pub use self::visible::*;
}
::pest::state(input, |state| match rule {
Rule::A => rules::A(state),
Rule::B => rules::B(state),
Rule::file => rules::file(state),
Rule::EOI => rules::EOI(state),
})
}
}
fn main() {}
rustfmt 1.5.1-nightly (20ffea69 2022-08-11)
Thanks for reaching out. I think this is likely related to #4476 #4867