diff --git a/src/items.rs b/src/items.rs index 0e814644304..cc55ea36d51 100644 --- a/src/items.rs +++ b/src/items.rs @@ -3325,7 +3325,20 @@ fn format_generics( used_width: usize, ) -> Option { let shape = Shape::legacy(context.budget(used_width + offset.width()), offset); - let mut result = rewrite_generics(context, "", generics, shape).ok()?; + let mut result = match rewrite_generics(context, "", generics, shape) { + Ok(r) => r, + Err(_) => { + // First attempt failed, try with infinite width for complex generics + let wide_shape = shape.infinite_width(); + match rewrite_generics(context, "", generics, wide_shape) { + Ok(r) => r, + Err(_) => { + // If even that fails, preserve original formatting from source + context.snippet(generics.span).to_string() + } + } + } + }; // If the generics are not parameterized then generics.span.hi() == 0, // so we use span.lo(), which is the position after `struct Foo`. diff --git a/tests/source/issue-6571.rs b/tests/source/issue-6571.rs new file mode 100644 index 00000000000..ffc2e232961 --- /dev/null +++ b/tests/source/issue-6571.rs @@ -0,0 +1,16 @@ +// Regression test for panic when formatting very long generic constraints +// This used to cause rustfmt to panic at src/items.rs:556 with "Option::unwrap() on a None value" +pub enum TestEnum< + T: std::collections::HashMap>> + Clone + Default + PartialEq + Eq + std::fmt::Debug + serde::Serialize + serde::Deserialize<'static> + Send + Sync + 'static = std::collections::HashMap>>, +> { + Variant1(T), + Variant2 { field: T }, +} + +// More realistic example from real codebase +pub enum ElementInit< + P: wrt_foundation::MemoryProvider + Clone + Default + PartialEq + Eq = wrt_foundation::NoStdProvider<1024>, +> { + FuncIndices(crate::WasmVec), + Expressions(crate::WasmVec, P>), +} diff --git a/tests/target/issue-6571.rs b/tests/target/issue-6571.rs new file mode 100644 index 00000000000..ffc2e232961 --- /dev/null +++ b/tests/target/issue-6571.rs @@ -0,0 +1,16 @@ +// Regression test for panic when formatting very long generic constraints +// This used to cause rustfmt to panic at src/items.rs:556 with "Option::unwrap() on a None value" +pub enum TestEnum< + T: std::collections::HashMap>> + Clone + Default + PartialEq + Eq + std::fmt::Debug + serde::Serialize + serde::Deserialize<'static> + Send + Sync + 'static = std::collections::HashMap>>, +> { + Variant1(T), + Variant2 { field: T }, +} + +// More realistic example from real codebase +pub enum ElementInit< + P: wrt_foundation::MemoryProvider + Clone + Default + PartialEq + Eq = wrt_foundation::NoStdProvider<1024>, +> { + FuncIndices(crate::WasmVec), + Expressions(crate::WasmVec, P>), +}