Repository: shepmaster/snafu (Rust)

Issue:
Cannot use a generic with a whatever variant 
The following code does not compile due to a missing generic on a generated impl block:

```rust
use snafu::Snafu;

#[derive(Snafu)]
enum Error<T: std::fmt::Display> {
    #[snafu(display("X"))]
    X { thing: T },
    #[snafu(whatever, display("{message}"))]
    Custom {
        message: String,
        #[snafu(source(from(Box<dyn std::error::Error>, Some)))]
        source: Option<Box<dyn std::error::Error>>,
    },
}
```

Expanded:

```rust
or more information about this error, try `rustc --explain E0412`.

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use snafu::Snafu;
enum Error<T: std::fmt::Display> {
    #[snafu(display("X"))]
    X { thing: T },
    #[snafu(whatever, display("{message}"))]
    Custom {
        message: String,
        #[snafu(source(from(Box<dyn std::error::Error>, Some)))]
        source: Option<Box<dyn std::error::Error>>,
    },
}
///SNAFU context selector for the `Error::X` variant
struct XSnafu<__T0> {
    #[allow(missing_docs)]
    thing: __T0,
}
#[automatically_derived]
impl<__T0: ::core::fmt::Debug> ::core::fmt::Debug for XSnafu<__T0> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(
            f,
            "XSnafu",
            "thing",
            &&self.thing,
        )
    }
}
#[automatically_derived]
impl<__T0: ::core::marker::Copy> ::core::marker::Copy for XSnafu<__T0> {}
#[automatically_derived]
impl<__T0: ::core::clone::Clone> ::core::clone::Clone for XSnafu<__T0> {
    #[inline]
    fn clone(&self) -> XSnafu<__T0> {
        XSnafu {
            thing: ::core::clone::Clone::clone(&self.thing),
        }
    }
}
impl<__T0> XSnafu<__T0> {
    ///Consume the selector and return the associated error
    #[must_use]
    #[track_caller]
    fn build<T: std::fmt::Display>(self) -> Error<T>
    where
        __T0: ::core::convert::Into<T>,
    {
        Error::X {
            thing: ::core::convert::Into::into(self.thing),
        }
    }
    ///Consume the selector and return a `Result` with the associated error
    #[track_caller]
    fn fail<T: std::fmt::Display, __T>(self) -> ::core::result::Result<__T, Error<T>>
    where
        __T0: ::core::convert::Into<T>,
    {
        ::core::result::Result::Err(self.build())
    }
}
impl<T: std::fmt::Display, __T0> ::snafu::IntoError<Error<T>> for XSnafu<__T0>
where
    Error<T>: ::snafu::Error + ::snafu::ErrorCompat,
    __T0: ::core::convert::Into<T>,
{
    type Source = ::snafu::NoneError;
    #[track_caller]
    fn into_error(self, error: Self::Source) -> Error<T> {
        Error::X {
            thing: ::core::convert::Into::into(self.thing),
        }
    }
}
impl ::snafu::FromString for Error<T> {
    type Source = Box<dyn std::error::Error>;
    #[track_caller]
    fn without_source(message: String) -> Self {
        Error::Custom {
            source: core::option::Option::None,
            message: message,
        }
    }
    #[track_caller]
    fn with_source(error: Self::Source, message: String) -> Self {
        Error::Custom {
            source: (Some)(error),
            message: message,
        }
    }
}
#[allow(single_use_lifetimes)]
impl<T: std::fmt::Display> ::core::fmt::Display for Error<T> {
    fn fmt(
        &self,
        __snafu_display_formatter: &mut ::core::fmt::Formatter,
    ) -> ::core::fmt::Result {
        #[allow(unused_variables)]
        match *self {
            Error::X { ref thing } => {
                __snafu_display_formatter.write_fmt(format_args!("X"))
            }
            Error::Custom { ref message, ref source } => {
                __snafu_display_formatter.write_fmt(format_args!("{0}", message))
            }
        }
    }
}
#[allow(single_use_lifetimes)]
impl<T: std::fmt::Display> ::snafu::Error for Error<T>
where
    Self: ::core::fmt::Debug + ::core::fmt::Display,
{
    fn description(&self) -> &str {
        match *self {
            Error::X { .. } => "Error :: X",
            Error::Custom { .. } => "Error :: Custom",
        }
    }
    fn cause(&self) -> ::core::option::Option<&dyn ::snafu::Error> {
        use ::snafu::AsErrorSource;
        match *self {
            Error::X { .. } => ::core::option::Option::None,
            Error::Custom { ref source, .. } => {
                source.as_ref().map(|e| e.as_error_source())
            }
        }
    }
    fn source(&self) -> ::core::option::Option<&(dyn ::snafu::Error + 'static)> {
        use ::snafu::AsErrorSource;
        match *self {
            Error::X { .. } => ::core::option::Option::None,
            Error::Custom { ref source, .. } => {
                source.as_ref().map(|e| e.as_error_source())
            }
        }
    }
}
#[allow(single_use_lifetimes)]
impl<T: std::fmt::Display> ::snafu::ErrorCompat for Error<T> {
    fn backtrace(&self) -> ::core::option::Option<&::snafu::Backtrace> {
        match *self {
            Error::X { .. } => ::core::option::Option::None,
            Error::Custom { .. } => ::core::option::Option::None,
        }
    }
}
```


Discussion:

Patch:
diff --git a/snafu-derive/src/shared.rs b/snafu-derive/src/shared.rs
index 6e6da13d..b30dd292 100644
--- a/snafu-derive/src/shared.rs
+++ b/snafu-derive/src/shared.rs
@@ -358,8 +358,10 @@ pub mod context_selector {
             let parameterized_error_name = self.parameterized_error_name;
             let error_constructor_name = self.error_constructor_name;
             let construct_implicit_fields = self.construct_implicit_fields();
+            let original_generics_without_defaults = self.original_generics_without_defaults;
             let construct_implicit_fields_with_source =
                 self.construct_implicit_fields_with_source();
+            let extended_where_clauses = self.extended_where_clauses();
 
             // testme: transform
 
@@ -381,7 +383,10 @@ pub mod context_selector {
             let message_field_name = &message_field.name;
 
             quote! {
-                impl #crate_root::FromString for #parameterized_error_name {
+                impl<#(#original_generics_without_defaults,)*> #crate_root::FromString for #parameterized_error_name
+                where
+                    #(#extended_where_clauses),*
+                {
                     type Source = #source_ty;
 
                     #[track_caller]


Test patch:
diff --git a/tests/generics.rs b/tests/generics.rs
index e9fe8178..6475cc6c 100644
--- a/tests/generics.rs
+++ b/tests/generics.rs
@@ -62,6 +62,13 @@ mod bounds {
         enum Error<T: Display> {
             #[snafu(display("Boom: {value}"))]
             Boom { value: T },
+
+            #[snafu(whatever, display("{message}"))]
+            Whatever {
+                message: String,
+                #[snafu(source(from(Box<dyn std::error::Error>, Some)))]
+                source: Option<Box<dyn std::error::Error>>,
+            },
         }
 
         #[test]
@@ -88,6 +95,13 @@ mod bounds {
         {
             #[snafu(display("Boom: {value}"))]
             Boom { value: T },
+
+            #[snafu(whatever, display("{message}"))]
+            Whatever {
+                message: String,
+                #[snafu(source(from(Box<dyn std::error::Error>, Some)))]
+                source: Option<Box<dyn std::error::Error>>,
+            },
         }
 
         #[test]