Repository: JelteF/derive_more (Rust)

Issue:
Optional source for Error
I’d like to be able to use `derive_more` with optional sources, like:

```rs
#[derive(derive_more::Error, derive_more::Display, Debug)]
#[display("it’s an error")]
struct MyErr {
    source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
}
```

Notably, this does work with `thiserror`.

At the moment this gives:

```
error[E0599]: the method `as_dyn_error` exists for enum `Option<Box<dyn Error + Send + Sync>>`, but its trait bounds were not satisfied
    |
187 | #[derive(derive_more::Error, derive_more::Display, Debug)]
    |          ^^^^^^^^^^^^^^^^^^
    |
571 | pub enum Option<T> {
    | ------------------ doesn't satisfy `_: AsDynError<'_>` or `_: Error`
    |
    = note: the following trait bounds were not satisfied:
            `std::option::Option<std::boxed::Box<dyn derive_more::Error + std::marker::Send + std::marker::Sync>>: derive_more::Error`
            which is required by `std::option::Option<std::boxed::Box<dyn derive_more::Error + std::marker::Send + std::marker::Sync>>: derive_more::__private::AsDynError<'_>`
note: the method `as_dyn_error` exists on the type `std::boxed::Box<(dyn derive_more::Error + std::marker::Send + std::marker::Sync + 'static)>`
    |
9   |     fn as_dyn_error(&self) -> &(dyn Error + 'a);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the derive macro `derive_more::Error` (in Nightly builds, run with -Z macro-backtrace for more info)
```


Discussion:
@tyranron thanks!



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b3e44f2..cbd75721 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 - Support `#[display(rename_all = "<casing>")]` attribute to change output for
   implicit naming of unit enum variants or unit structs when deriving `Display`.
   ([#443](https://github.com/JelteF/derive_more/pull/443))
+- Support `Option` fields for `Error::source()` in `Error` derive.
+  ([#459](https://github.com/JelteF/derive_more/pull/459))
 
 ### Fixed
 
diff --git a/impl/doc/error.md b/impl/doc/error.md
index 2aace519..ad41c926 100644
--- a/impl/doc/error.md
+++ b/impl/doc/error.md
@@ -52,6 +52,38 @@ Backtraces don't work though, because the `Backtrace` type is only available in
 `std`.
 
 
+### `Option`al fields
+
+Deriving `source()` is supported naturally for `Option<_>`-typed fields.
+
+> **WARNING**: Field type is **considered as `Option<_>` only syntactically**,
+> meaning that:
+> - Neither renaming `std::option::Option` would work:
+>   ```rust,compile_fail
+>   # use derive_more::{Display, Error};
+>   #
+>   #[derive(Debug, Display, Error)]
+>   struct Simple;
+>
+>   #[derive(Debug, Display, Error)]
+>   #[display("Oops!")]
+>   struct Generic(RenamedOption<Simple>); // not recognized as `Option`
+>   type RenamedOption<T> = Option<T>;
+>   ```
+> - Nor using any custom type named as `Option` would:
+>   ```rust,compile_fail
+>   # use derive_more::{Display, Error};
+>   #
+>   # #[derive(Debug, Display, Error)]
+>   # struct Simple;
+>   #
+>   #[derive(Debug, Display, Error)]
+>   #[display("No way!")]
+>   struct Generic(Option<Simple>);        // cannot use `?` syntax
+>   struct Option<T>(T);
+>   ```
+
+
 
 
 ## Example usage
@@ -79,10 +111,21 @@ struct WithSource {
     source: Simple,
 }
 #[derive(Default, Debug, Display, Error)]
+#[display("WithOptionalSource")]
+struct WithOptionalSource {
+    source: Option<Simple>,
+}
+#[derive(Default, Debug, Display, Error)]
 struct WithExplicitSource {
     #[error(source)]
     explicit_source: Simple,
 }
+#[derive(Default, Debug, Display, Error)]
+#[display("WithExplicitOptionalSource")]
+struct WithExplicitOptionalSource {
+    #[error(source)]
+    explicit_source: Option<Simple>,
+}
 
 #[derive(Default, Debug, Display, Error)]
 struct Tuple(Simple);
@@ -104,6 +147,10 @@ enum CompoundError {
     WithSource {
         source: Simple,
     },
+    #[display("WithOptionalSource")]
+    WithOptionalSource {
+        source: Option<Simple>,
+    },
     #[from(ignore)]
     WithBacktraceFromSource {
         #[error(backtrace)]
@@ -118,21 +165,35 @@ enum CompoundError {
         #[error(source)]
         explicit_source: WithSource,
     },
+    #[display("WithExplicitOptionalSource")]
+    WithExplicitOptionalSource {
+        #[error(source)]
+        explicit_source: Option<WithSource>,
+    },
     #[from(ignore)]
     WithBacktraceFromExplicitSource {
         #[error(backtrace, source)]
         explicit_source: WithSource,
     },
     Tuple(WithExplicitSource),
+    #[display("TupleOptional")]
+    TupleOptional(Option<WithExplicitSource>),
     WithoutSource(#[error(not(source))] Tuple),
 }
 
 assert!(Simple.source().is_none());
 assert!(request_ref::<Backtrace>(&Simple).is_none());
+
 assert!(WithSource::default().source().is_some());
+assert!(WithOptionalSource { source: Some(Simple) }.source().is_some());
+
 assert!(WithExplicitSource::default().source().is_some());
+assert!(WithExplicitOptionalSource { explicit_source: Some(Simple) }.source().is_some());
+
 assert!(Tuple::default().source().is_some());
+
 assert!(WithoutSource::default().source().is_none());
+
 let with_source_and_backtrace = WithSourceAndBacktrace {
     source: Simple,
     backtrace: Backtrace::capture(),
@@ -141,9 +202,16 @@ assert!(with_source_and_backtrace.source().is_some());
 assert!(request_ref::<Backtrace>(&with_source_and_backtrace).is_some());
 
 assert!(CompoundError::Simple.source().is_none());
+
 assert!(CompoundError::from(Simple).source().is_some());
+assert!(CompoundError::from(Some(Simple)).source().is_some());
+
 assert!(CompoundError::from(WithSource::default()).source().is_some());
+assert!(CompoundError::from(Some(WithSource::default())).source().is_some());
+
 assert!(CompoundError::from(WithExplicitSource::default()).source().is_some());
+assert!(CompoundError::from(Some(WithExplicitSource::default())).source().is_some());
+
 assert!(CompoundError::from(Tuple::default()).source().is_none());
 # }
 ```
diff --git a/impl/src/error.rs b/impl/src/error.rs
index 76382d18..be6c1052 100644
--- a/impl/src/error.rs
+++ b/impl/src/error.rs
@@ -43,7 +43,7 @@ pub fn expand(
             // TODO: Use `derive_more::core::error::Error` once `error_in_core` Rust feature is
             //       stabilized.
             fn source(&self) -> Option<&(dyn derive_more::with_trait::Error + 'static)> {
-                use derive_more::__private::AsDynError;
+                use derive_more::__private::AsDynError as _;
                 #source
             }
         }
@@ -207,13 +207,17 @@ impl ParsedFields<'_, '_> {
     fn render_source_as_struct(&self) -> Option<TokenStream> {
         let source = self.source?;
         let ident = &self.data.members[source];
-        Some(render_some(quote! { #ident }))
+        Some(render_some(
+            quote! { (&#ident) },
+            self.data.field_types[source].is_option(),
+        ))
     }
 
     fn render_source_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
         let source = self.source?;
         let pattern = self.data.matcher(&[source], &[quote! { source }]);
-        let expr = render_some(quote! { source });
+        let expr =
+            render_some(quote! { source }, self.data.field_types[source].is_option());
         Some(quote! { #pattern => #expr })
     }
 
@@ -287,10 +291,10 @@ impl ParsedFields<'_, '_> {
     }
 }
 
-fn render_some<T>(expr: T) -> TokenStream
-where
-    T: quote::ToTokens,
-{
+fn render_some(mut expr: TokenStream, unpack: bool) -> TokenStream {
+    if unpack {
+        expr = quote! { derive_more::core::option::Option::as_ref(#expr)? }
+    }
     quote! { Some(#expr.as_dyn_error()) }
 }
 
@@ -500,6 +504,42 @@ fn add_bound_if_type_parameter_used_in_type(
     ty: &syn::Type,
 ) {
     if let Some(ty) = utils::get_if_type_parameter_used_in_type(type_params, ty) {
-        bounds.insert(ty);
+        bounds.insert(ty.get_option_inner().cloned().unwrap_or(ty));
+    }
+}
+
+/// Extension of a [`syn::Type`] used by this expansion.
+trait TypeExt {
+    /// Checks syntactically whether this [`syn::Type`] represents an [`Option`].
+    fn is_option(&self) -> bool;
+
+    /// Returns the inner [`syn::Type`] if this one represents an [`Option`].
+    fn get_option_inner(&self) -> Option<&Self>;
+}
+
+impl TypeExt for syn::Type {
+    fn is_option(&self) -> bool {
+        self.get_option_inner().is_some()
+    }
+
+    fn get_option_inner(&self) -> Option<&Self> {
+        match self {
+            Self::Group(g) => g.elem.get_option_inner(),
+            Self::Paren(p) => p.elem.get_option_inner(),
+            Self::Path(p) => p
+                .path
+                .segments
+                .last()
+                .filter(|s| s.ident == "Option")
+                .and_then(|s| {
+                    if let syn::PathArguments::AngleBracketed(a) = &s.arguments {
+                        if let Some(syn::GenericArgument::Type(ty)) = a.args.first() {
+                            return Some(ty);
+                        }
+                    }
+                    None
+                }),
+            _ => None,
+        }
     }
 }


Test patch:
diff --git a/tests/error/derives_for_enums_with_source.rs b/tests/error/derives_for_enums_with_source.rs
index e5c6c360..3de323a9 100644
--- a/tests/error/derives_for_enums_with_source.rs
+++ b/tests/error/derives_for_enums_with_source.rs
@@ -13,11 +13,20 @@ enum TestErr {
         source: SimpleErr,
         field: i32,
     },
+    NamedImplicitOptionalSource {
+        source: Option<SimpleErr>,
+        field: i32,
+    },
     #[cfg(feature = "std")]
     NamedImplicitBoxedSource {
         source: Box<dyn Error + Send + 'static>,
         field: i32,
     },
+    #[cfg(feature = "std")]
+    NamedImplicitOptionalBoxedSource {
+        source: Option<Box<dyn Error + Send + 'static>>,
+        field: i32,
+    },
     NamedExplicitNoSource {
         #[error(not(source))]
         source: SimpleErr,
@@ -28,6 +37,11 @@ enum TestErr {
         explicit_source: SimpleErr,
         field: i32,
     },
+    NamedExplicitOptionalSource {
+        #[error(source)]
+        explicit_source: Option<SimpleErr>,
+        field: i32,
+    },
     NamedExplicitNoSourceRedundant {
         #[error(not(source))]
         field: i32,
@@ -37,20 +51,33 @@ enum TestErr {
         source: SimpleErr,
         field: i32,
     },
+    NamedExplicitOptionalSourceRedundant {
+        #[error(source)]
+        source: Option<SimpleErr>,
+        field: i32,
+    },
     NamedExplicitSuppressesImplicit {
         source: i32,
         #[error(source)]
         field: SimpleErr,
     },
+    NamedExplicitOptionalSuppressesImplicit {
+        source: i32,
+        #[error(source)]
+        field: Option<SimpleErr>,
+    },
     UnnamedImplicitNoSource(i32, i32),
     UnnamedImplicitSource(SimpleErr),
+    UnnamedImplicitOptionalSource(Option<SimpleErr>),
     UnnamedExplicitNoSource(#[error(not(source))] SimpleErr),
     UnnamedExplicitSource(#[error(source)] SimpleErr, i32),
+    UnnamedExplicitOptionalSource(#[error(source)] Option<SimpleErr>, i32),
     UnnamedExplicitNoSourceRedundant(
         #[error(not(source))] i32,
         #[error(not(source))] i32,
     ),
     UnnamedExplicitSourceRedundant(#[error(source)] SimpleErr),
+    UnnamedExplicitOptionalSourceRedundant(#[error(source)] Option<SimpleErr>),
     NamedIgnore {
         #[error(ignore)]
         source: SimpleErr,
@@ -100,6 +127,17 @@ fn named_implicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_implicit_optional_source() {
+    let err = TestErr::NamedImplicitOptionalSource {
+        source: Some(SimpleErr),
+        field: 0,
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[cfg(feature = "std")]
 #[test]
 fn named_implicit_boxed_source() {
@@ -112,6 +150,18 @@ fn named_implicit_boxed_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[cfg(feature = "std")]
+#[test]
+fn named_implicit_optional_boxed_source() {
+    let err = TestErr::NamedImplicitOptionalBoxedSource {
+        source: Some(Box::new(SimpleErr)),
+        field: 0,
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn named_explicit_no_source() {
     let err = TestErr::NamedExplicitNoSource {
@@ -133,6 +183,17 @@ fn named_explicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_explicit_optional_source() {
+    let err = TestErr::NamedExplicitOptionalSource {
+        explicit_source: Some(SimpleErr),
+        field: 0,
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn named_explicit_no_source_redundant() {
     let err = TestErr::NamedExplicitNoSourceRedundant { field: 0 };
@@ -151,6 +212,17 @@ fn named_explicit_source_redundant() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_explicit_optional_source_redundant() {
+    let err = TestErr::NamedExplicitOptionalSourceRedundant {
+        source: Some(SimpleErr),
+        field: 0,
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn named_explicit_suppresses_implicit() {
     let err = TestErr::NamedExplicitSuppressesImplicit {
@@ -162,6 +234,17 @@ fn named_explicit_suppresses_implicit() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_explicit_optional_suppresses_implicit() {
+    let err = TestErr::NamedExplicitOptionalSuppressesImplicit {
+        source: 0,
+        field: Some(SimpleErr),
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn unnamed_implicit_no_source() {
     assert!(TestErr::UnnamedImplicitNoSource(0, 0).source().is_none());
@@ -175,6 +258,14 @@ fn unnamed_implicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn unnamed_implicit_optional_source() {
+    let err = TestErr::UnnamedImplicitOptionalSource(Some(SimpleErr));
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn unnamed_explicit_no_source() {
     let err = TestErr::UnnamedExplicitNoSource(SimpleErr);
@@ -190,6 +281,14 @@ fn unnamed_explicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn unnamed_explicit_optional_source() {
+    let err = TestErr::UnnamedExplicitOptionalSource(Some(SimpleErr), 0);
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn unnamed_explicit_no_source_redundant() {
     let err = TestErr::UnnamedExplicitNoSourceRedundant(0, 0);
@@ -205,6 +304,14 @@ fn unnamed_explicit_source_redundant() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn unnamed_explicit_optional_source_redundant() {
+    let err = TestErr::UnnamedExplicitOptionalSourceRedundant(Some(SimpleErr));
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn named_ignore() {
     let err = TestErr::NamedIgnore {
diff --git a/tests/error/derives_for_generic_enums_with_source.rs b/tests/error/derives_for_generic_enums_with_source.rs
index 5067043c..2b10638a 100644
--- a/tests/error/derives_for_generic_enums_with_source.rs
+++ b/tests/error/derives_for_generic_enums_with_source.rs
@@ -13,6 +13,10 @@ enum TestErr<E, T> {
         source: E,
         field: T,
     },
+    NamedImplicitOptionalSource {
+        source: Option<E>,
+        field: T,
+    },
     NamedExplicitNoSource {
         #[error(not(source))]
         source: E,
@@ -23,6 +27,11 @@ enum TestErr<E, T> {
         explicit_source: E,
         field: T,
     },
+    NamedExplicitOptionalSource {
+        #[error(source)]
+        explicit_source: Option<E>,
+        field: T,
+    },
     NamedExplicitNoSourceRedundant {
         #[error(not(source))]
         field: T,
@@ -32,17 +41,30 @@ enum TestErr<E, T> {
         source: E,
         field: T,
     },
+    NamedExplicitOptionalSourceRedundant {
+        #[error(source)]
+        source: Option<E>,
+        field: T,
+    },
     NamedExplicitSuppressesImplicit {
         source: T,
         #[error(source)]
         field: E,
     },
+    NamedExplicitOptionalSuppressesImplicit {
+        source: T,
+        #[error(source)]
+        field: Option<E>,
+    },
     UnnamedImplicitNoSource(T, T),
     UnnamedImplicitSource(E),
+    UnnamedImplicitOptionalSource(Option<E>),
     UnnamedExplicitNoSource(#[error(not(source))] E),
     UnnamedExplicitSource(#[error(source)] E, T),
+    UnnamedExplicitOptionalSource(#[error(source)] Option<E>, T),
     UnnamedExplicitNoSourceRedundant(#[error(not(source))] T, #[error(not(source))] T),
     UnnamedExplicitSourceRedundant(#[error(source)] E),
+    UnnamedExplicitOptionalSourceRedundant(#[error(source)] Option<E>),
     NamedIgnore {
         #[error(ignore)]
         source: E,
@@ -92,6 +114,17 @@ fn named_implicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_implicit_optional_source() {
+    let err = TestErr::NamedImplicitOptionalSource {
+        source: Some(SimpleErr),
+        field: 0,
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn named_explicit_no_source() {
     let err = TestErr::NamedExplicitNoSource {
@@ -113,6 +146,17 @@ fn named_explicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_explicit_optional_source() {
+    let err = TestErr::NamedExplicitOptionalSource {
+        explicit_source: Some(SimpleErr),
+        field: 0,
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn named_explicit_no_source_redundant() {
     let err = TestErr::<SimpleErr, _>::NamedExplicitNoSourceRedundant { field: 0 };
@@ -131,6 +175,17 @@ fn named_explicit_source_redundant() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_explicit_optional_source_redundant() {
+    let err = TestErr::NamedExplicitOptionalSourceRedundant {
+        source: Some(SimpleErr),
+        field: 0,
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn named_explicit_suppresses_implicit() {
     let err = TestErr::NamedExplicitSuppressesImplicit {
@@ -142,6 +197,17 @@ fn named_explicit_suppresses_implicit() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn named_explicit_optional_suppresses_implicit() {
+    let err = TestErr::NamedExplicitOptionalSuppressesImplicit {
+        source: 0,
+        field: Some(SimpleErr),
+    };
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn unnamed_implicit_no_source() {
     let err = TestErr::<SimpleErr, _>::UnnamedImplicitNoSource(0, 0);
@@ -157,6 +223,14 @@ fn unnamed_implicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn unnamed_implicit_optional_source() {
+    let err = TestErr::<_, i32>::UnnamedImplicitOptionalSource(Some(SimpleErr));
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn unnamed_explicit_no_source() {
     let err = TestErr::<_, i32>::UnnamedExplicitNoSource(SimpleErr);
@@ -172,6 +246,14 @@ fn unnamed_explicit_source() {
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
 
+#[test]
+fn unnamed_explicit_optional_source() {
+    let err = TestErr::UnnamedExplicitOptionalSource(Some(SimpleErr), 0);
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
 #[test]
 fn unnamed_explicit_no_source_redundant() {
     let err = TestErr::<SimpleErr, _>::UnnamedExplicitNoSourceRedundant(0, 0);
@@ -180,8 +262,9 @@ fn unnamed_explicit_no_source_redundant() {
 }
 
 #[test]
-fn unnamed_explicit_source_redundant() {
-    let err = TestErr::<_, i32>::UnnamedExplicitSourceRedundant(SimpleErr);
+fn unnamed_explicit_optional_source_redundant() {
+    let err =
+        TestErr::<_, i32>::UnnamedExplicitOptionalSourceRedundant(Some(SimpleErr));
 
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
diff --git a/tests/error/derives_for_generic_structs_with_source.rs b/tests/error/derives_for_generic_structs_with_source.rs
index 64266367..e4b633c3 100644
--- a/tests/error/derives_for_generic_structs_with_source.rs
+++ b/tests/error/derives_for_generic_structs_with_source.rs
@@ -23,6 +23,25 @@ fn named_implicit_source() {
     }
 
     let err = TestErr::<SimpleErr, i32>::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_implicit_optional_source() {
+    derive_display!(TestErr, E, T);
+    #[derive(Default, Debug, Error)]
+    struct TestErr<E, T> {
+        source: Option<E>,
+        field: T,
+    }
+
+    let err = TestErr::<_, i32> {
+        source: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -38,6 +57,7 @@ fn named_explicit_no_source() {
     }
 
     let err = TestErr::<SimpleErr, i32>::default();
+
     assert!(err.source().is_none());
 }
 
@@ -52,6 +72,26 @@ fn named_explicit_source() {
     }
 
     let err = TestErr::<SimpleErr, i32>::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_explicit_optional_source() {
+    derive_display!(TestErr, E, T);
+    #[derive(Default, Debug, Error)]
+    struct TestErr<E, T> {
+        #[error(source)]
+        explicit_source: Option<E>,
+        field: T,
+    }
+
+    let err = TestErr::<_, i32> {
+        explicit_source: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -79,6 +119,26 @@ fn named_explicit_source_redundant() {
     }
 
     let err = TestErr::<SimpleErr, i32>::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_explicit_optional_source_redundant() {
+    derive_display!(TestErr, E, T);
+    #[derive(Default, Debug, Error)]
+    struct TestErr<E, T> {
+        #[error(source)]
+        source: Option<E>,
+        field: T,
+    }
+
+    let err = TestErr::<_, i32> {
+        source: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -94,6 +154,26 @@ fn named_explicit_suppresses_implicit() {
     }
 
     let err = TestErr::<i32, SimpleErr>::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_explicit_optional_suppresses_implicit() {
+    derive_display!(TestErr, E, T);
+    #[derive(Default, Debug, Error)]
+    struct TestErr<E, T> {
+        source: E,
+        #[error(source)]
+        field: Option<T>,
+    }
+
+    let err = TestErr::<i32, _> {
+        field: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -114,6 +194,19 @@ fn unnamed_implicit_source() {
     struct TestErr<E>(E);
 
     let err = TestErr::<SimpleErr>::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn unnamed_implicit_optional_source() {
+    derive_display!(TestErr, E);
+    #[derive(Default, Debug, Error)]
+    struct TestErr<E>(Option<E>);
+
+    let err = TestErr(Some(SimpleErr));
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -134,6 +227,22 @@ fn unnamed_explicit_source() {
     struct TestErr<E, T>(#[error(source)] E, T);
 
     let err = TestErr::<SimpleErr, i32>::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn unnamed_explicit_optional_source() {
+    derive_display!(TestErr, E, T);
+    #[derive(Default, Debug, Error)]
+    struct TestErr<E, T>(#[error(source)] Option<E>, T);
+
+    let err = TestErr::<_, i32> {
+        0: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -154,6 +263,19 @@ fn unnamed_explicit_source_redundant() {
     struct TestErr<E>(#[error(source)] E);
 
     let err = TestErr::<SimpleErr>::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn unnamed_explicit_optional_source_redundant() {
+    derive_display!(TestErr, E);
+    #[derive(Default, Debug, Error)]
+    struct TestErr<E>(#[error(source)] Option<E>);
+
+    let err = TestErr(Some(SimpleErr));
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
diff --git a/tests/error/derives_for_structs_with_source.rs b/tests/error/derives_for_structs_with_source.rs
index 2267c16e..c14c0bcb 100644
--- a/tests/error/derives_for_structs_with_source.rs
+++ b/tests/error/derives_for_structs_with_source.rs
@@ -28,6 +28,25 @@ fn named_implicit_source() {
     }
 
     let err = TestErr::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_implicit_optional_source() {
+    derive_display!(TestErr);
+    #[derive(Default, Debug, Error)]
+    struct TestErr {
+        source: Option<SimpleErr>,
+        field: i32,
+    }
+
+    let err = TestErr {
+        source: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -56,6 +75,26 @@ fn named_explicit_source() {
     }
 
     let err = TestErr::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_explicit_optional_source() {
+    derive_display!(TestErr);
+    #[derive(Default, Debug, Error)]
+    struct TestErr {
+        #[error(source)]
+        explicit_source: Option<SimpleErr>,
+        field: i32,
+    }
+
+    let err = TestErr {
+        explicit_source: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -83,6 +122,26 @@ fn named_explicit_source_redundant() {
     }
 
     let err = TestErr::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_explicit_optional_source_redundant() {
+    derive_display!(TestErr);
+    #[derive(Default, Debug, Error)]
+    struct TestErr {
+        #[error(source)]
+        source: Option<SimpleErr>,
+        field: i32,
+    }
+
+    let err = TestErr {
+        source: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -98,6 +157,26 @@ fn named_explicit_suppresses_implicit() {
     }
 
     let err = TestErr::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn named_explicit_optional_suppresses_implicit() {
+    derive_display!(TestErr);
+    #[derive(Default, Debug, Error)]
+    struct TestErr {
+        source: i32,
+        #[error(source)]
+        field: Option<SimpleErr>,
+    }
+
+    let err = TestErr {
+        field: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -118,6 +197,19 @@ fn unnamed_implicit_source() {
     struct TestErr(SimpleErr);
 
     let err = TestErr::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn unnamed_implicit_optional_source() {
+    derive_display!(TestErr);
+    #[derive(Default, Debug, Error)]
+    struct TestErr(Option<SimpleErr>);
+
+    let err = TestErr(Some(SimpleErr));
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -138,6 +230,22 @@ fn unnamed_explicit_source() {
     struct TestErr(#[error(source)] SimpleErr, i32);
 
     let err = TestErr::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn unnamed_explicit_optional_source() {
+    derive_display!(TestErr);
+    #[derive(Default, Debug, Error)]
+    struct TestErr(#[error(source)] Option<SimpleErr>, i32);
+
+    let err = TestErr {
+        0: Some(SimpleErr),
+        ..TestErr::default()
+    };
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }
@@ -158,6 +266,19 @@ fn unnamed_explicit_source_redundant() {
     struct TestErr(#[error(source)] SimpleErr);
 
     let err = TestErr::default();
+
+    assert!(err.source().is_some());
+    assert!(err.source().unwrap().is::<SimpleErr>());
+}
+
+#[test]
+fn unnamed_explicit_optional_source_redundant() {
+    derive_display!(TestErr);
+    #[derive(Default, Debug, Error)]
+    struct TestErr(#[error(source)] Option<SimpleErr>);
+
+    let err = TestErr(Some(SimpleErr));
+
     assert!(err.source().is_some());
     assert!(err.source().unwrap().is::<SimpleErr>());
 }