Repository: zkat/miette
Pull request #41 (2021-08-30 03:38:04)

Add `#[diagnostic(forward(field_name), code(...))]`
This PR solves a problem I imagined. Not sure if it's real or not yet. I made a demo though: https://gist.github.com/cormacrelf/09ef573df0f5b41c9fa252f5866336ba

There are bugfix components of this that unquestionably need to be merged, but they were done on top of the other work so I'd have to redo it basically.

As described in #36:

> The forwarding branch, in addition to that, adds a forward(field_name) arg that must be used with a code(...) like any other arg. When you supply it, it makes any unspecified things forward their implementation to the specified field. It works with named and unnamed (forward(0)) structs and enum variants. The test suite shows what you can do with it -- the ForwardsTo struct is used for the snippets, all the other bits of info can be overridden.
>
> The question before we land this PR is a bikeshed, whether these two different argument names for arguably the same functionality are a good idea or not. Which is preferable of these?
>
> -    Only diagnostic(transparent)
> -    diagnostic(transparent), diagnostic(code(...), forward(field_name)) as described
> -    diagnostic(transparent), diagnostic(code(...), transparent(field_name))
> -    diagnostic(transparent), diagnostic(code(...), default(field_name). I kinda like this but I only just thought of it.



zkat: quick comment: I went to some lengths to make sure that all the `gen` methods were infallible, so any issues would be found out as early as possible, during the parsing phase. I haven't read this PR in detail yet, but it would be nice if we could keep those infallible generators.
cormacrelf: Ah yes, originally I peppered a few Results in there, but realised what you were going for later. I just forgot to remove the Result from the main gen() method. It did indeed turn out cleaner with the fallible parts in the parse phase.
cormacrelf: One side benefit is that for use of transparent on structs with !=1 field, what used to be a rendered `_ => compile_error!("...")`  is now a properly spanned error, since it's now `DiagnosticDefArgs::Transparent(Forward)` constructed with `Forward::for_transparent_field()?`.
zkat: hey how's it going with this? Just a heads up that I'm about to start making some potentially really big breaking changes to the way snippets are defined and I'm afraid to conflict with this stuff.
cormacrelf: I did mark it draft, but there's nothing left to do.
cormacrelf: Basically it's whether you want it or not!
cormacrelf: Actually there are some conflicts now, thumbs up react if you want me to resolve em
zkat: Please go ahead
cormacrelf: The failing tests are the same ones that are failing on main due to a change in the number of `-------` after printing the code

Patch:
diff --git a/miette-derive/src/code.rs b/miette-derive/src/code.rs
index 35bc189..59aa436 100644
--- a/miette-derive/src/code.rs
+++ b/miette-derive/src/code.rs
@@ -7,8 +7,9 @@ use syn::{
 };
 
 use crate::{
-    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef, DiagnosticDefArgs},
-    utils::forward_to_single_field_variant,
+    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
+    forward::WhichFn,
+    utils::gen_all_variants_with,
 };
 
 #[derive(Debug)]
@@ -48,41 +49,24 @@ impl Parse for Code {
 
 impl Code {
     pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
-        let code_pairs = variants.iter().map(
-            |DiagnosticDef {
-                 ident,
-                 fields,
-                 args,
-             }| {
-                match args {
-                    DiagnosticDefArgs::Transparent => {
-                        Some(forward_to_single_field_variant(ident, fields, quote! { code() }))
+        gen_all_variants_with(
+            variants,
+            WhichFn::Code,
+            |ident, fields, DiagnosticConcreteArgs { code, .. }| {
+                let code = &code.as_ref()?.0;
+                Some(match fields {
+                    syn::Fields::Named(_) => {
+                        quote! { Self::#ident { .. } => std::option::Option::Some(std::boxed::Box::new(#code)), }
                     }
-                    DiagnosticDefArgs::Concrete(DiagnosticConcreteArgs { code, .. }) => {
-                        let code = &code.as_ref()?.0;
-                        Some(match fields {
-                            syn::Fields::Named(_) => {
-                                quote! { Self::#ident { .. } => std::option::Option::Some(std::boxed::Box::new(#code)), }
-                            }
-                            syn::Fields::Unnamed(_) => {
-                                quote! { Self::#ident(..) => std::option::Option::Some(std::boxed::Box::new(#code)), }
-                            }
-                            syn::Fields::Unit => {
-                                quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(#code)), }
-                            }
-                        })
+                    syn::Fields::Unnamed(_) => {
+                        quote! { Self::#ident(..) => std::option::Option::Some(std::boxed::Box::new(#code)), }
                     }
-                }
+                    syn::Fields::Unit => {
+                        quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(#code)), }
+                    }
+                })
             },
-        );
-        Some(quote! {
-            fn code<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
-                match self {
-                    #(#code_pairs)*
-                    _ => std::option::Option::None,
-                }
-            }
-        })
+        )
     }
 
     pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
diff --git a/miette-derive/src/diagnostic.rs b/miette-derive/src/diagnostic.rs
index 249aba6..db75868 100644
--- a/miette-derive/src/diagnostic.rs
+++ b/miette-derive/src/diagnostic.rs
@@ -1,9 +1,10 @@
 use proc_macro2::TokenStream;
-use quote::{format_ident, quote};
+use quote::quote;
 use syn::{punctuated::Punctuated, DeriveInput, Token};
 
 use crate::code::Code;
 use crate::diagnostic_arg::DiagnosticArg;
+use crate::forward::{Forward, WhichFn};
 use crate::help::Help;
 use crate::severity::Severity;
 use crate::snippets::Snippets;
@@ -30,10 +31,29 @@ pub struct DiagnosticDef {
 }
 
 pub enum DiagnosticDefArgs {
-    Transparent,
+    Transparent(Forward),
     Concrete(DiagnosticConcreteArgs),
 }
 
+impl DiagnosticDefArgs {
+    pub(crate) fn forward_or_override_enum(
+        &self,
+        variant: &syn::Ident,
+        which_fn: WhichFn,
+        mut f: impl FnMut(&DiagnosticConcreteArgs) -> Option<TokenStream>,
+    ) -> Option<TokenStream> {
+        match self {
+            Self::Transparent(forward) => Some(forward.gen_enum_match_arm(variant, which_fn)),
+            Self::Concrete(concrete) => f(concrete).or_else(|| {
+                concrete
+                    .forward
+                    .as_ref()
+                    .map(|forward| forward.gen_enum_match_arm(variant, which_fn))
+            }),
+        }
+    }
+}
+
 #[derive(Default)]
 pub struct DiagnosticConcreteArgs {
     pub code: Option<Code>,
@@ -41,6 +61,7 @@ pub struct DiagnosticConcreteArgs {
     pub help: Option<Help>,
     pub snippets: Option<Snippets>,
     pub url: Option<Url>,
+    pub forward: Option<Forward>,
 }
 
 impl DiagnosticConcreteArgs {
@@ -54,11 +75,15 @@ impl DiagnosticConcreteArgs {
         let mut severity = None;
         let mut help = None;
         let mut url = None;
+        let mut forward = None;
         for arg in args {
             match arg {
                 DiagnosticArg::Transparent => {
                     return Err(syn::Error::new_spanned(attr, "transparent not allowed"));
                 }
+                DiagnosticArg::Forward(to_field) => {
+                    forward = Some(to_field);
+                }
                 DiagnosticArg::Code(new_code) => {
                     // TODO: error on multiple?
                     code = Some(new_code);
@@ -81,6 +106,7 @@ impl DiagnosticConcreteArgs {
             severity,
             snippets,
             url,
+            forward,
         };
         Ok(concrete)
     }
@@ -92,14 +118,15 @@ impl DiagnosticDefArgs {
         fields: &syn::Fields,
         attr: &syn::Attribute,
         allow_transparent: bool,
-    ) -> Result<Self, syn::Error> {
+    ) -> syn::Result<Self> {
         let args =
             attr.parse_args_with(Punctuated::<DiagnosticArg, Token![,]>::parse_terminated)?;
         if allow_transparent
             && args.len() == 1
             && matches!(args.first(), Some(DiagnosticArg::Transparent))
         {
-            return Ok(Self::Transparent);
+            let forward = Forward::for_transparent_field(fields)?;
+            return Ok(Self::Transparent(forward));
         } else if args.iter().any(|x| matches!(x, DiagnosticArg::Transparent)) {
             return Err(syn::Error::new_spanned(
                 attr,
@@ -177,65 +204,55 @@ impl Diagnostic {
             } => {
                 let (impl_generics, ty_generics, where_clause) = &generics.split_for_impl();
                 match args {
-                    DiagnosticDefArgs::Transparent => {
-                        if fields.iter().len() != 1 {
-                            return quote! {
-                                compile_error!("you can only use #[diagnostic(transparent)] on a struct with exactly one field");
-                            };
-                        }
-                        let field = fields
-                            .iter()
-                            .next()
-                            .expect("MIETTE BUG: thought we knew we had exactly one field");
-                        let field_name = field
-                            .ident
-                            .clone()
-                            .unwrap_or_else(|| format_ident!("unnamed"));
-                        let matcher = match fields {
-                            syn::Fields::Named(_) => quote! { let Self { #field_name } = self; },
-                            syn::Fields::Unnamed(_) => quote! { let Self(#field_name) = self; },
-                            syn::Fields::Unit => {
-                                unreachable!("MIETTE BUG: thought we knew we had exactly one field")
-                            }
-                        };
+                    DiagnosticDefArgs::Transparent(forward) => {
+                        let code_method = forward.gen_struct_method(WhichFn::Code);
+                        let help_method = forward.gen_struct_method(WhichFn::Help);
+                        let url_method = forward.gen_struct_method(WhichFn::Url);
+                        let severity_method = forward.gen_struct_method(WhichFn::Severity);
+                        let snippets_method = forward.gen_struct_method(WhichFn::Snippets);
 
                         quote! {
                             impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause {
-                                fn code<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
-                                    #matcher
-                                    #field_name.code()
-                                }
-                                fn help<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
-                                    #matcher
-                                    #field_name.help()
-                                }
-                                fn url<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
-                                    #matcher
-                                    #field_name.url()
-                                }
-                                fn severity(&self) -> std::option::Option<miette::Severity> {
-                                    #matcher
-                                    #field_name.severity()
-                                }
-                                fn snippets(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::DiagnosticSnippet> + '_>> {
-                                    #matcher
-                                    #field_name.snippets()
-                                }
+                                #code_method
+                                #help_method
+                                #url_method
+                                #severity_method
+                                #snippets_method
                             }
                         }
                     }
                     DiagnosticDefArgs::Concrete(concrete) => {
-                        let code_body = concrete.code.as_ref().and_then(|x| x.gen_struct());
-                        let help_body = concrete.help.as_ref().and_then(|x| x.gen_struct(fields));
-                        let sev_body = concrete.severity.as_ref().and_then(|x| x.gen_struct());
+                        let forward = |which| {
+                            concrete
+                                .forward
+                                .as_ref()
+                                .map(|fwd| fwd.gen_struct_method(which))
+                        };
+                        let code_body = concrete
+                            .code
+                            .as_ref()
+                            .and_then(|x| x.gen_struct())
+                            .or_else(|| forward(WhichFn::Code));
+                        let help_body = concrete
+                            .help
+                            .as_ref()
+                            .and_then(|x| x.gen_struct(fields))
+                            .or_else(|| forward(WhichFn::Help));
+                        let sev_body = concrete
+                            .severity
+                            .as_ref()
+                            .and_then(|x| x.gen_struct())
+                            .or_else(|| forward(WhichFn::Severity));
                         let snip_body = concrete
                             .snippets
                             .as_ref()
-                            .and_then(|x| x.gen_struct(fields));
+                            .and_then(|x| x.gen_struct(fields))
+                            .or_else(|| forward(WhichFn::Snippets));
                         let url_body = concrete
                             .url
                             .as_ref()
-                            .and_then(|x| x.gen_struct(ident, fields));
+                            .and_then(|x| x.gen_struct(ident, fields))
+                            .or_else(|| forward(WhichFn::Url));
 
                         quote! {
                             impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause {
diff --git a/miette-derive/src/diagnostic_arg.rs b/miette-derive/src/diagnostic_arg.rs
index e56cc7a..bade6f0 100644
--- a/miette-derive/src/diagnostic_arg.rs
+++ b/miette-derive/src/diagnostic_arg.rs
@@ -1,6 +1,7 @@
 use syn::parse::{Parse, ParseStream};
 
 use crate::code::Code;
+use crate::forward::Forward;
 use crate::help::Help;
 use crate::severity::Severity;
 use crate::url::Url;
@@ -11,6 +12,7 @@ pub enum DiagnosticArg {
     Severity(Severity),
     Help(Help),
     Url(Url),
+    Forward(Forward),
 }
 
 impl Parse for DiagnosticArg {
@@ -20,6 +22,8 @@ impl Parse for DiagnosticArg {
             // consume the token
             let _: syn::Ident = input.parse()?;
             Ok(DiagnosticArg::Transparent)
+        } else if ident == "forward" {
+            Ok(DiagnosticArg::Forward(input.parse()?))
         } else if ident == "code" {
             Ok(DiagnosticArg::Code(input.parse()?))
         } else if ident == "severity" {
diff --git a/miette-derive/src/forward.rs b/miette-derive/src/forward.rs
new file mode 100644
index 0000000..6c7b539
--- /dev/null
+++ b/miette-derive/src/forward.rs
@@ -0,0 +1,150 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use syn::{
+    parenthesized,
+    parse::{Parse, ParseStream},
+    spanned::Spanned,
+};
+
+pub enum Forward {
+    Unnamed(usize),
+    Named(syn::Ident),
+}
+
+impl Parse for Forward {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        let forward = input.parse::<syn::Ident>()?;
+        if forward != "forward" {
+            return Err(syn::Error::new(forward.span(), "msg"));
+        }
+        let content;
+        parenthesized!(content in input);
+        let looky = content.lookahead1();
+        if looky.peek(syn::LitInt) {
+            let int: syn::LitInt = content.parse()?;
+            let index = int.base10_parse()?;
+            return Ok(Forward::Unnamed(index));
+        }
+        Ok(Forward::Named(content.parse()?))
+    }
+}
+
+#[derive(Copy, Clone)]
+pub enum WhichFn {
+    Code,
+    Help,
+    Url,
+    Severity,
+    Snippets,
+}
+
+impl WhichFn {
+    pub fn method_call(&self) -> TokenStream {
+        match self {
+            Self::Code => quote! { code() },
+            Self::Help => quote! { help() },
+            Self::Url => quote! { url() },
+            Self::Severity => quote! { severity() },
+            Self::Snippets => quote! { snippets() },
+        }
+    }
+
+    pub fn signature(&self) -> TokenStream {
+        match self {
+            Self::Code => quote! {
+                fn code<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>>
+            },
+            Self::Help => quote! {
+                fn help<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>>
+            },
+            Self::Url => quote! {
+                fn url<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>>
+            },
+            Self::Severity => quote! {
+                fn severity(&self) -> std::option::Option<miette::Severity>
+            },
+            Self::Snippets => quote! {
+                fn snippets(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::DiagnosticSnippet> + '_>>
+            },
+        }
+    }
+
+    pub fn catchall_arm(&self) -> TokenStream {
+        match self {
+            // required, hence method can't return None
+            Self::Code => quote! {},
+            _ => quote! { _ => None, },
+        }
+    }
+}
+
+impl Forward {
+    pub fn for_transparent_field(fields: &syn::Fields) -> syn::Result<Self> {
+        let make_err = || {
+            syn::Error::new(
+                fields.span(),
+                "you can only use #[diagnostic(transparent)] with exactly one field",
+            )
+        };
+        match fields {
+            syn::Fields::Named(named) => {
+                let mut iter = named.named.iter();
+                let field = iter.next().ok_or_else(make_err)?;
+                if iter.next().is_some() {
+                    return Err(make_err());
+                }
+                let field_name = field
+                    .ident
+                    .clone()
+                    .unwrap_or_else(|| format_ident!("unnamed"));
+                Ok(Self::Named(field_name))
+            }
+            syn::Fields::Unnamed(unnamed) => {
+                if unnamed.unnamed.iter().len() != 1 {
+                    return Err(make_err());
+                }
+                Ok(Self::Unnamed(0))
+            }
+            _ => Err(syn::Error::new(
+                fields.span(),
+                "you cannot use #[diagnostic(transparent)] with a unit struct or a unit variant",
+            )),
+        }
+    }
+
+    pub fn gen_struct_method(&self, which_fn: WhichFn) -> TokenStream {
+        let signature = which_fn.signature();
+        let method_call = which_fn.method_call();
+
+        let field_name = match self {
+            Forward::Named(field_name) => quote!(#field_name),
+            Forward::Unnamed(index) => {
+                let index = syn::Index::from(*index);
+                quote!(#index)
+            }
+        };
+
+        quote! {
+            #[inline]
+            #signature {
+                self.#field_name.#method_call
+            }
+        }
+    }
+
+    pub fn gen_enum_match_arm(&self, variant: &syn::Ident, which_fn: WhichFn) -> TokenStream {
+        let method_call = which_fn.method_call();
+        match self {
+            Forward::Named(field_name) => quote! {
+                Self::#variant { #field_name, .. } => #field_name.#method_call,
+            },
+            Forward::Unnamed(index) => {
+                let underscores: Vec<_> = core::iter::repeat(quote! { _, }).take(*index).collect();
+                let unnamed = format_ident!("unnamed");
+                quote! {
+                    Self::#variant ( #(#underscores)* #unnamed, .. ) => #unnamed.#method_call,
+                }
+            }
+        }
+    }
+}
diff --git a/miette-derive/src/help.rs b/miette-derive/src/help.rs
index 35154fa..c8879ca 100644
--- a/miette-derive/src/help.rs
+++ b/miette-derive/src/help.rs
@@ -1,18 +1,18 @@
-use std::collections::HashSet;
-
 use proc_macro2::TokenStream;
-use quote::{format_ident, quote};
+use quote::quote;
 use syn::{
     parenthesized,
     parse::{Parse, ParseStream},
-    spanned::Spanned,
     Fields, Token,
 };
 
-use crate::fmt::{self, Display};
 use crate::{
-    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef, DiagnosticDefArgs},
-    utils::forward_to_single_field_variant,
+    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
+    utils::{display_pat_members, gen_all_variants_with},
+};
+use crate::{
+    fmt::{self, Display},
+    forward::WhichFn,
 };
 
 pub struct Help {
@@ -31,7 +31,6 @@ impl Parse for Help {
                 let args = if content.is_empty() {
                     TokenStream::new()
                 } else {
-                    content.parse::<Token![,]>()?;
                     fmt::parse_token_expr(&content, false)?
                 };
                 let display = Display {
@@ -58,110 +57,28 @@ impl Parse for Help {
 
 impl Help {
     pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
-        let help_pairs = variants
-            .iter()
-            .map(
-                |DiagnosticDef {
-                     ident,
-                     fields,
-                     args,
-                     ..
-                 }| {
-                     match args {
-                         DiagnosticDefArgs::Transparent => {
-                             Some(forward_to_single_field_variant(ident, fields, quote!{ help() } ))
-                         }
-                         DiagnosticDefArgs::Concrete(DiagnosticConcreteArgs { help, .. }) => {
-                             let mut display = help.as_ref()?.display.clone();
-                             let member_idents = fields.iter().enumerate().map(|(i, field)| {
-                                 field
-                                     .ident
-                                     .as_ref()
-                                     .cloned()
-                                     .unwrap_or_else(|| format_ident!("_{}", i))
-                             });
-                             let members: HashSet<syn::Member> = fields.iter().enumerate().map(|(i, field)| {
-                                 if let Some(ident) = field.ident.as_ref().cloned() {
-                                     syn::Member::Named(ident)
-                                 } else {
-                                     syn::Member::Unnamed(syn::Index { index: i as u32, span: field.span() })
-                                 }
-                             }).collect();
-                             display.expand_shorthand(&members);
-                             let Display { fmt, args, .. } = display;
-                             Some(match fields {
-                                 syn::Fields::Named(_) => {
-                                     quote! { Self::#ident{ #(#member_idents),* } => std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args))), }
-                                 }
-                                 syn::Fields::Unnamed(_) => {
-                                     quote! { Self::#ident( #(#member_idents),* ) => std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args))), }
-                                 }
-                                 syn::Fields::Unit =>
-                                     quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args))), },
-                             })
-                         }
-                     }
-                 },
-            )
-            .flatten()
-            .collect::<Vec<_>>();
-        if help_pairs.is_empty() {
-            None
-        } else {
-            Some(quote! {
-                fn help<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
-                    #[allow(unused_variables, deprecated)]
-                    match self {
-                        #(#help_pairs)*
-                        _ => None,
-                    }
-                }
-            })
-        }
+        gen_all_variants_with(
+            variants,
+            WhichFn::Help,
+            |ident, fields, DiagnosticConcreteArgs { help, .. }| {
+                let (display_pat, display_members) = display_pat_members(fields);
+                let display = &help.as_ref()?.display;
+                let (fmt, args) = display.expand_shorthand_cloned(&display_members);
+                Some(quote! {
+                    Self::#ident #display_pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
+                })
+            },
+        )
     }
 
     pub(crate) fn gen_struct(&self, fields: &Fields) -> Option<TokenStream> {
-        let mut display = self.display.clone();
-        let members: HashSet<syn::Member> = fields
-            .iter()
-            .enumerate()
-            .map(|(i, field)| {
-                if let Some(ident) = field.ident.as_ref().cloned() {
-                    syn::Member::Named(ident)
-                } else {
-                    syn::Member::Unnamed(syn::Index {
-                        index: i as u32,
-                        span: field.span(),
-                    })
-                }
-            })
-            .collect();
-        display.expand_shorthand(&members);
-        let members = members.iter();
-        let Display { fmt, args, .. } = display;
-        let fields_pat = match fields {
-            Fields::Named(_) => quote! {
-                let Self { #(#members),* } = self;
-            },
-            Fields::Unnamed(_) => {
-                let vars = members.map(|member| {
-                    if let syn::Member::Unnamed(member) = member {
-                        format_ident!("_{}", member)
-                    } else {
-                        unreachable!()
-                    }
-                });
-                quote! {
-                    let Self(#(#vars),*) = self;
-                }
-            }
-            Fields::Unit => quote! {},
-        };
+        let (display_pat, display_members) = display_pat_members(fields);
+        let (fmt, args) = self.display.expand_shorthand_cloned(&display_members);
         Some(quote! {
             fn help<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
                 #[allow(unused_variables, deprecated)]
-                #fields_pat
-                std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args)))
+                let Self #display_pat = self;
+                std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args)))
             }
         })
     }
diff --git a/miette-derive/src/lib.rs b/miette-derive/src/lib.rs
index 9a6d616..c99f813 100644
--- a/miette-derive/src/lib.rs
+++ b/miette-derive/src/lib.rs
@@ -7,6 +7,7 @@ mod code;
 mod diagnostic;
 mod diagnostic_arg;
 mod fmt;
+mod forward;
 mod help;
 mod severity;
 mod snippets;
diff --git a/miette-derive/src/severity.rs b/miette-derive/src/severity.rs
index d828335..4f26e4e 100644
--- a/miette-derive/src/severity.rs
+++ b/miette-derive/src/severity.rs
@@ -7,8 +7,9 @@ use syn::{
 };
 
 use crate::{
-    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef, DiagnosticDefArgs},
-    utils::forward_to_single_field_variant,
+    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
+    forward::WhichFn,
+    utils::gen_all_variants_with,
 };
 
 pub struct Severity(pub syn::Ident);
@@ -60,42 +61,21 @@ fn get_severity(input: &str, span: Span) -> syn::Result<String> {
 
 impl Severity {
     pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
-        let sev_pairs = variants
-            .iter()
-            .map(
-                |DiagnosticDef {
-                     ident, fields, args
-                 }| {
-                     match args {
-                         DiagnosticDefArgs::Transparent => {
-                             Some(forward_to_single_field_variant(ident, fields, quote!{ severity() }))
-                         }
-                         DiagnosticDefArgs::Concrete(DiagnosticConcreteArgs { severity, .. }) => {
-                             let severity = &severity.as_ref()?.0;
-                             let fields = match fields {
-                                 syn::Fields::Named(_) => quote! { { .. } },
-                                 syn::Fields::Unnamed(_) => quote! { (..) },
-                                 syn::Fields::Unit => quote!{},
-                             };
-                             Some(quote! { Self::#ident #fields => std::option::Option::Some(miette::Severity::#severity), })
-                         }
-                     }
-                },
-            )
-            .flatten()
-            .collect::<Vec<_>>();
-        if sev_pairs.is_empty() {
-            None
-        } else {
-            Some(quote! {
-               fn severity(&self) -> std::option::Option<miette::Severity> {
-                   match self {
-                        #(#sev_pairs)*
-                        _ => std::option::Option::None,
-                   }
-               }
-            })
-        }
+        gen_all_variants_with(
+            variants,
+            WhichFn::Severity,
+            |ident, fields, DiagnosticConcreteArgs { severity, .. }| {
+                let severity = &severity.as_ref()?.0;
+                let fields = match fields {
+                    syn::Fields::Named(_) => quote! { { .. } },
+                    syn::Fields::Unnamed(_) => quote! { (..) },
+                    syn::Fields::Unit => quote! {},
+                };
+                Some(
+                    quote! { Self::#ident #fields => std::option::Option::Some(miette::Severity::#severity), },
+                )
+            },
+        )
     }
 
     pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
diff --git a/miette-derive/src/snippets.rs b/miette-derive/src/snippets.rs
index fedc8e2..26a53b1 100644
--- a/miette-derive/src/snippets.rs
+++ b/miette-derive/src/snippets.rs
@@ -1,4 +1,4 @@
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
 
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
@@ -10,11 +10,10 @@ use syn::{
 };
 
 use crate::{
-    diagnostic::DiagnosticConcreteArgs, fmt::Display, utils::forward_to_single_field_variant,
-};
-use crate::{
-    diagnostic::{DiagnosticDef, DiagnosticDefArgs},
-    fmt,
+    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
+    fmt::{self, Display},
+    forward::WhichFn,
+    utils::{display_pat_members, gen_all_variants_with},
 };
 
 pub struct Snippets(Vec<Snippet>);
@@ -57,7 +56,6 @@ impl Parse for SnippetAttr {
                         let args = if content.is_empty() {
                             TokenStream::new()
                         } else {
-                            content.parse::<Token![,]>()?;
                             fmt::parse_token_expr(&content, false)?
                         };
                         let display = Display {
@@ -106,7 +104,6 @@ impl Parse for HighlightAttr {
                         let args = if content.is_empty() {
                             TokenStream::new()
                         } else {
-                            content.parse::<Token![,]>()?;
                             fmt::parse_token_expr(&content, false)?
                         };
                         let display = Display {
@@ -210,28 +207,15 @@ impl Snippets {
     }
 
     pub(crate) fn gen_struct(&self, fields: &syn::Fields) -> Option<TokenStream> {
+        let (display_pat, display_members) = display_pat_members(fields);
         let snippets = self.0.iter().map(|snippet| {
             // snippet message
             let msg = if let Some(display) = &snippet.message {
-                let members: HashSet<syn::Member> = fields
-                    .iter()
-                    .enumerate()
-                    .map(|(i, field)| {
-                        if let Some(ident) = field.ident.as_ref().cloned() {
-                            syn::Member::Named(ident)
-                        } else {
-                            syn::Member::Unnamed(syn::Index {
-                                index: i as u32,
-                                span: field.span(),
-                            })
-                        }
-                    })
-                    .collect();
-                let mut display = display.clone();
-                display.expand_shorthand(&members);
-                let Display { fmt, args, .. } = display;
+                let (fmt, args) = display.expand_shorthand_cloned(&display_members);
                 quote! {
-                    message: std::option::Option::Some(format!(#fmt, #args)),
+                    message: {
+                        std::option::Option::Some(format!(#fmt #args))
+                    },
                 }
             } else {
                 quote! {
@@ -254,12 +238,11 @@ impl Snippets {
             // Highlights
             let highlights = snippet.highlights.iter().map(|highlight| {
                 let Highlight { highlight, label } = highlight;
-                if let Some(Display { fmt, args, .. }) = label {
+                if let Some(display) = label {
+                    let (fmt, args) = display.expand_shorthand_cloned(&display_members);
                     quote! {
                         (
-                            std::option::Option::Some(
-                                format!(#fmt, #args)
-                            ),
+                            std::option::Option::Some(format!(#fmt #args)),
                             self.#highlight.clone().into()
                         )
                     }
@@ -288,6 +271,7 @@ impl Snippets {
         Some(quote! {
             #[allow(unused_variables)]
             fn snippets(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::DiagnosticSnippet> + '_>> {
+                let Self #display_pat = self;
                 Some(Box::new(vec![
                     #(#snippets),*
                 ].into_iter()))
@@ -296,31 +280,16 @@ impl Snippets {
     }
 
     pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
-        let variant_arms = variants.iter().map(|variant| {
-            let DiagnosticDef { ident, fields, args: def_args } = variant;
-            match def_args {
-                DiagnosticDefArgs::Transparent => {
-                    Some(forward_to_single_field_variant(
-                        ident,
-                        fields,
-                        quote! { snippets() },
-                    ))
-                }
-                DiagnosticDefArgs::Concrete(DiagnosticConcreteArgs { snippets, .. }) => {
-                    snippets.as_ref().and_then(|snippets| {
+        gen_all_variants_with(
+            variants,
+            WhichFn::Snippets,
+            |ident, fields, DiagnosticConcreteArgs { snippets, .. }| {
+                let (display_pat, display_members) = display_pat_members(fields);
+                snippets.as_ref().and_then(|snippets| {
                         let variant_snippets = snippets.0.iter().map(|snippet| {
                             // snippet message
                             let msg = if let Some(display) = &snippet.message {
-                            let members: HashSet<syn::Member> = variant.fields.iter().enumerate().map(|(i, field)| {
-                                if let Some(ident) = field.ident.as_ref().cloned() {
-                                    syn::Member::Named(ident)
-                                } else {
-                                    syn::Member::Unnamed(syn::Index { index: i as u32, span: field.span() })
-                                }
-                            }).collect();
-                                let mut display = display.clone();
-                                display.expand_shorthand(&members);
-                                let Display { fmt, args, .. } = display;
+                                let (fmt, args) = display.expand_shorthand_cloned(&display_members);
                                 quote! {
                                     message: std::option::Option::Some(format!(#fmt, #args)),
                                 }
@@ -390,40 +359,17 @@ impl Snippets {
                                 }
                             }
                         });
-                        let variant_name = variant.ident.clone();
-                        let members = variant.fields.iter().enumerate().map(|(i, field)| {
-                            field
-                                .ident
-                                .as_ref()
-                                .cloned()
-                                .unwrap_or_else(|| format_ident!("_{}", i))
-                        });
-                        match &variant.fields {
+                        let variant_name = ident.clone();
+                        match &fields {
                             syn::Fields::Unit => None,
-                            syn::Fields::Named(_) => Some(quote! {
-                                Self::#variant_name { #(#members),* } => std::option::Option::Some(std::boxed::Box::new(vec![
-                                    #(#variant_snippets),*
-                                ].into_iter())),
-                            }),
-                            syn::Fields::Unnamed(_) => Some(quote! {
-                                Self::#variant_name(#(#members),*) => std::option::Option::Some(Box::new(vec![
+                            _ => Some(quote! {
+                                Self::#variant_name #display_pat => std::option::Option::Some(std::boxed::Box::new(vec![
                                     #(#variant_snippets),*
                                 ].into_iter())),
                             }),
                         }
                     })
-                }
-            }
-        })
-        .flatten();
-        Some(quote! {
-            #[allow(unused_variables)]
-            fn snippets(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::DiagnosticSnippet> + '_>> {
-                match self {
-                    #(#variant_arms)*
-                    _ => std::option::Option::None,
-                }
-            }
-        })
+            },
+        )
     }
 }
diff --git a/miette-derive/src/url.rs b/miette-derive/src/url.rs
index 080e0ca..24f2739 100644
--- a/miette-derive/src/url.rs
+++ b/miette-derive/src/url.rs
@@ -1,18 +1,18 @@
-use std::collections::HashSet;
-
 use proc_macro2::TokenStream;
-use quote::{format_ident, quote};
+use quote::quote;
 use syn::{
     parenthesized,
     parse::{Parse, ParseStream},
-    spanned::Spanned,
     Fields, Token,
 };
 
-use crate::fmt::{self, Display};
 use crate::{
-    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef, DiagnosticDefArgs},
-    utils::forward_to_single_field_variant,
+    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
+    utils::{display_pat_members, gen_all_variants_with, gen_unused_pat},
+};
+use crate::{
+    fmt::{self, Display},
+    forward::WhichFn,
 };
 
 pub enum Url {
@@ -33,7 +33,6 @@ impl Parse for Url {
                     let args = if content.is_empty() {
                         TokenStream::new()
                     } else {
-                        content.parse::<Token![,]>()?;
                         fmt::parse_token_expr(&content, false)?
                     };
                     let display = Display {
@@ -69,78 +68,37 @@ impl Url {
         enum_name: &syn::Ident,
         variants: &[DiagnosticDef],
     ) -> Option<TokenStream> {
-        let url_pairs = variants.iter().map(|variant| {
-            let DiagnosticDef { ident, fields, args: def_args } = variant;
-            match def_args {
-                DiagnosticDefArgs::Transparent => {
-                    Some(forward_to_single_field_variant(
-                        ident,
-                        fields,
-                        quote! { url() },
-                    ))
-                }
-                DiagnosticDefArgs::Concrete(DiagnosticConcreteArgs { ref url, .. }) => {
-                    let member_idents = fields.iter().enumerate().map(|(i, field)| {
-                        field
-                            .ident
-                            .as_ref()
-                            .cloned()
-                            .unwrap_or_else(|| format_ident!("_{}", i))
-                    });
-                    let members: HashSet<syn::Member> = fields.iter().enumerate().map(|(i, field)| {
-                        if let Some(ident) = field.ident.as_ref().cloned() {
-                            syn::Member::Named(ident)
-                        } else {
-                            syn::Member::Unnamed(syn::Index { index: i as u32, span: field.span() })
-                        }
-                    }).collect();
-                    let (fmt, args) = match url.as_ref()? {
-                        // fall through to `_ => None` below
-                        Url::Display(display) => {
-                            let mut display = display.clone();
-                            display.expand_shorthand(&members);
-                            let Display { fmt, args, .. } = display;
-                            (fmt.value(), args)
-                        }
-                        Url::DocsRs => {
-                            let fmt = "https://docs.rs/{crate_name}/{crate_version}/{crate_name}/{item_path}".into();
-                            let item_path = format!("enum.{}.html#variant.{}", enum_name, ident);
-                            let args = quote! {
-                                crate_name=env!("CARGO_PKG_NAME"),
-                                crate_version=env!("CARGO_PKG_VERSION"),
-                                item_path=#item_path
-                            };
-                            (fmt, args)
-                        }
-                    };
-                    Some(match fields {
-                        syn::Fields::Named(_) => {
-                            quote! { Self::#ident{ #(#member_idents),* } => std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args))), }
-                        }
-                        syn::Fields::Unnamed(_) => {
-                            quote! { Self::#ident( #(#member_idents),* ) => std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args))), }
-                        }
-                        syn::Fields::Unit =>
-                            quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args))), },
-                    })
-                }
-            }
-         })
-        .flatten()
-        .collect::<Vec<_>>();
-        if url_pairs.is_empty() {
-            None
-        } else {
-            Some(quote! {
-                fn url<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
-                    #[allow(unused_variables, deprecated)]
-                    match self {
-                        #(#url_pairs)*
-                        _ => None,
+        gen_all_variants_with(
+            variants,
+            WhichFn::Url,
+            |ident, fields, DiagnosticConcreteArgs { url, .. }| {
+                let (pat, fmt, args) = match url.as_ref()? {
+                    // fall through to `_ => None` below
+                    Url::Display(display) => {
+                        let (display_pat, display_members) = display_pat_members(fields);
+                        let (fmt, args) = display.expand_shorthand_cloned(&display_members);
+                        (display_pat, fmt.value(), args)
                     }
-                }
-            })
-        }
+                    Url::DocsRs => {
+                        let pat = gen_unused_pat(fields);
+                        let fmt =
+                            "https://docs.rs/{crate_name}/{crate_version}/{crate_name}/{item_path}"
+                                .into();
+                        let item_path = format!("enum.{}.html#variant.{}", enum_name, ident);
+                        let args = quote! {
+                            ,
+                            crate_name=env!("CARGO_PKG_NAME"),
+                            crate_version=env!("CARGO_PKG_VERSION"),
+                            item_path=#item_path
+                        };
+                        (pat, fmt, args)
+                    }
+                };
+                Some(quote! {
+                    Self::#ident #pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
+                })
+            },
+        )
     }
 
     pub(crate) fn gen_struct(
@@ -148,63 +106,31 @@ impl Url {
         struct_name: &syn::Ident,
         fields: &Fields,
     ) -> Option<TokenStream> {
-        let members: HashSet<syn::Member> = fields
-            .iter()
-            .enumerate()
-            .map(|(i, field)| {
-                if let Some(ident) = field.ident.as_ref().cloned() {
-                    syn::Member::Named(ident)
-                } else {
-                    syn::Member::Unnamed(syn::Index {
-                        index: i as u32,
-                        span: field.span(),
-                    })
-                }
-            })
-            .collect();
-        let (fmt, args) = match self {
+        let (pat, fmt, args) = match self {
             Url::Display(display) => {
-                let mut display = display.clone();
-                display.expand_shorthand(&members);
-                let Display { fmt, args, .. } = display;
-                (fmt.value(), args)
+                let (display_pat, display_members) = display_pat_members(fields);
+                let (fmt, args) = display.expand_shorthand_cloned(&display_members);
+                (display_pat, fmt.value(), args)
             }
             Url::DocsRs => {
+                let pat = gen_unused_pat(fields);
                 let fmt =
                     "https://docs.rs/{crate_name}/{crate_version}/{crate_name}/{item_path}".into();
                 let item_path = format!("struct.{}.html", struct_name);
                 let args = quote! {
+                    ,
                     crate_name=env!("CARGO_PKG_NAME"),
                     crate_version=env!("CARGO_PKG_VERSION"),
                     item_path=#item_path
                 };
-                (fmt, args)
-            }
-        };
-        let members = members.iter();
-        let fields_pat = match fields {
-            Fields::Named(_) => quote! {
-                let Self { #(#members),* } = self;
-            },
-            Fields::Unnamed(_) => {
-                let vars = members.map(|member| {
-                    if let syn::Member::Unnamed(member) = member {
-                        format_ident!("_{}", member)
-                    } else {
-                        unreachable!()
-                    }
-                });
-                quote! {
-                    let Self(#(#vars),*) = self;
-                }
+                (pat, fmt, args)
             }
-            Fields::Unit => quote! {},
         };
         Some(quote! {
             fn url<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
                 #[allow(unused_variables, deprecated)]
-                #fields_pat
-                std::option::Option::Some(std::boxed::Box::new(format!(#fmt, #args)))
+                let Self #pat = self;
+                std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args)))
             }
         })
     }
diff --git a/miette-derive/src/utils.rs b/miette-derive/src/utils.rs
index 428b14f..1172016 100644
--- a/miette-derive/src/utils.rs
+++ b/miette-derive/src/utils.rs
@@ -1,6 +1,9 @@
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote, ToTokens};
-use syn::parse::{Parse, ParseStream};
+use syn::{
+    parse::{Parse, ParseStream},
+    spanned::Spanned,
+};
 
 pub(crate) enum MemberOrString {
     Member(syn::Member),
@@ -33,34 +36,103 @@ impl Parse for MemberOrString {
     }
 }
 
-// bool here is whether to use curly braces
-pub fn single_field_name(fields: &syn::Fields) -> Option<(bool, &syn::Field)> {
+use crate::{
+    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
+    forward::WhichFn,
+};
+
+pub(crate) fn gen_all_variants_with(
+    variants: &[DiagnosticDef],
+    which_fn: WhichFn,
+    mut f: impl FnMut(&syn::Ident, &syn::Fields, &DiagnosticConcreteArgs) -> Option<TokenStream>,
+) -> Option<TokenStream> {
+    let pairs = variants
+        .iter()
+        .map(|def| {
+            def.args
+                .forward_or_override_enum(&def.ident, which_fn, |concrete| {
+                    f(&def.ident, &def.fields, concrete)
+                })
+        })
+        .flatten()
+        .collect::<Vec<_>>();
+    if pairs.is_empty() {
+        return None;
+    }
+    let signature = which_fn.signature();
+    let catchall = which_fn.catchall_arm();
+    Some(quote! {
+        #signature {
+            #[allow(unused_variables, deprecated)]
+            match self {
+                #(#pairs)*
+                #catchall
+            }
+        }
+    })
+}
+
+use crate::fmt::Display;
+use std::collections::HashSet;
+
+pub(crate) fn gen_unused_pat(fields: &syn::Fields) -> TokenStream {
     match fields {
-        syn::Fields::Named(f) if f.named.len() == 1 => f.named.first().map(|x| (true, x)),
-        syn::Fields::Unnamed(f) if f.unnamed.len() == 1 => f.unnamed.first().map(|x| (false, x)),
-        _ => None,
+        syn::Fields::Named(_) => quote! { { .. } },
+        syn::Fields::Unnamed(_) => quote! { ( .. ) },
+        syn::Fields::Unit => quote! {},
     }
 }
 
-// Returns a match arm
-pub fn forward_to_single_field_variant(
-    ident: &syn::Ident,
-    fields: &syn::Fields,
-    method_call: TokenStream,
-) -> TokenStream {
-    if let Some((curly, single_field)) = single_field_name(fields) {
-        let field_name = single_field
+/// Goes in the slot `let Self #pat = self;` or `match self { Self #pat => ... }`.
+fn gen_fields_pat(fields: &syn::Fields) -> TokenStream {
+    let member_idents = fields.iter().enumerate().map(|(i, field)| {
+        field
             .ident
-            .clone()
-            .unwrap_or_else(|| format_ident!("unnamed"));
-        if curly {
-            quote! { Self::#ident { #field_name } => #field_name.#method_call, }
-        } else {
-            quote! { Self::#ident(#field_name) => #field_name.#method_call, }
-        }
-    } else {
-        quote! {
-            _ => compile_error!("miette: used `#[diagnostic(transparent)]` on variant without one single field"),
-        }
+            .as_ref()
+            .cloned()
+            .unwrap_or_else(|| format_ident!("_{}", i))
+    });
+    match fields {
+        syn::Fields::Named(_) => quote! {
+            { #(#member_idents),* }
+        },
+        syn::Fields::Unnamed(_) => quote! {
+            ( #(#member_idents),* )
+        },
+        syn::Fields::Unit => quote! {},
+    }
+}
+
+/// The returned tokens go in the slot `let Self #pat = self;` or `match self { Self #pat => ... }`.
+/// The members can be passed to `Display::expand_shorthand[_cloned]`.
+pub(crate) fn display_pat_members(fields: &syn::Fields) -> (TokenStream, HashSet<syn::Member>) {
+    let pat = gen_fields_pat(fields);
+    let members: HashSet<syn::Member> = fields
+        .iter()
+        .enumerate()
+        .map(|(i, field)| {
+            if let Some(ident) = field.ident.as_ref().cloned() {
+                syn::Member::Named(ident)
+            } else {
+                syn::Member::Unnamed(syn::Index {
+                    index: i as u32,
+                    span: field.span(),
+                })
+            }
+        })
+        .collect();
+    (pat, members)
+}
+
+impl Display {
+    /// Returns `(fmt, args)` which must be passed to some kind of format macro without tokens in between, i.e. `format!(#fmt #args)`.
+    pub(crate) fn expand_shorthand_cloned(
+        &self,
+        members: &HashSet<syn::Member>,
+    ) -> (syn::LitStr, TokenStream) {
+        let mut display = self.clone();
+        display.expand_shorthand(members);
+        let Display { fmt, args, .. } = display;
+        (fmt, args)
     }
 }


Test patch:
diff --git a/src/compile_test.rs b/src/compile_test.rs
index eeda312..790867f 100644
--- a/src/compile_test.rs
+++ b/src/compile_test.rs
@@ -92,3 +92,38 @@ struct SingleFieldTests;
 #[allow(dead_code)]
 #[doc(hidden)]
 struct TransparentCombinations;
+
+/// Forwarding without overriding the code (struct)
+///
+/// ```compile_fail
+/// use thiserror::Error;
+/// use miette_derive::Diagnostic;
+/// #[derive(Debug, Diagnostic, Error)]
+/// #[error("welp")]
+/// #[diagnostic(code(foo::bar::baz))]
+/// struct Foo {}
+/// #[derive(Debug, Diagnostic, Error)]
+/// #[error("welp")]
+/// #[diagnostic(forward(0))]
+/// struct Bar(Foo);
+/// ```
+///
+/// Forwarding without overriding the code (enum)
+///
+/// ```compile_fail
+/// use thiserror::Error;
+/// use miette_derive::Diagnostic;
+/// #[derive(Debug, Diagnostic, Error)]
+/// #[error("welp")]
+/// #[diagnostic(code(foo::bar::baz))]
+/// struct Foo {}
+/// #[derive(Debug, Diagnostic, Error)]
+/// enum Enum {
+/// #[error("welp")]
+/// #[diagnostic(forward(0))]
+/// Bar(Foo) }
+/// ```
+///
+#[allow(dead_code)]
+#[doc(hidden)]
+struct ForwardWithoutCode;
diff --git a/tests/derive.rs b/tests/derive.rs
index 9257650..44a8827 100644
--- a/tests/derive.rs
+++ b/tests/derive.rs
@@ -322,7 +322,8 @@ const SNIPPET_TEXT: &str = "hello from miette";
 #[derive(Debug, Diagnostic, Error)]
 #[error("welp")]
 #[diagnostic(
-    code(foo::bar::baz),
+    // code not necessary.
+    // code(foo::bar::baz),
     url("https://example.com"),
     help("help"),
     severity(Warning)
@@ -345,13 +346,16 @@ impl ForwardsTo {
     }
 }
 
-fn check_snippets(diag: &impl Diagnostic) {
+fn check_all(diag: &impl Diagnostic) {
     // check Diagnostic impl forwards all these methods
-    assert_eq!(diag.code().unwrap().to_string(), "foo::bar::baz");
+    assert_eq!(diag.code().as_ref().map(|x| x.to_string()), None);
     assert_eq!(diag.url().unwrap().to_string(), "https://example.com");
     assert_eq!(diag.help().unwrap().to_string(), "help");
     assert_eq!(diag.severity().unwrap(), miette::Severity::Warning);
+    check_snippets(diag);
+}
 
+fn check_snippets(diag: &impl Diagnostic) {
     type Snip = (Option<String>, usize, usize);
     let snips: Vec<(Snip, Vec<Snip>)> = diag
         .snippets()
@@ -394,7 +398,7 @@ fn test_transparent_enum_unnamed() {
 
     let variant = Enum::FooVariant(ForwardsTo::new());
 
-    check_snippets(&variant);
+    check_all(&variant);
 }
 
 #[test]
@@ -416,7 +420,7 @@ fn test_transparent_enum_named() {
         single_field: ForwardsTo::new(),
     };
 
-    check_snippets(&variant);
+    check_all(&variant);
 
     let bar_variant = Enum::BarVariant;
     assert_eq!(
@@ -436,7 +440,7 @@ fn test_transparent_struct_named() {
     }
     // Also check the From impl here
     let variant: Struct = ForwardsTo::new().into();
-    check_snippets(&variant);
+    check_all(&variant);
 }
 
 #[test]
@@ -446,5 +450,113 @@ fn test_transparent_struct_unnamed() {
     #[diagnostic(transparent)]
     struct Struct(#[from] ForwardsTo);
     let variant = Struct(ForwardsTo::new());
+    check_all(&variant);
+}
+
+#[test]
+fn test_forward_struct_named() {
+    #[derive(Debug, Diagnostic, Error)]
+    #[error("display")]
+    #[diagnostic(
+        code(foo::bar::overridden),
+        severity(Advice),
+        help("{help}"),
+        forward(span)
+    )]
+    struct Struct {
+        span: ForwardsTo,
+        help: &'static str,
+    }
+    // Also check the From impl here
+    let diag = Struct {
+        span: ForwardsTo::new(),
+        help: "overridden help please",
+    };
+    assert_eq!(diag.code().unwrap().to_string(), "foo::bar::overridden");
+    assert_eq!(diag.help().unwrap().to_string(), "overridden help please");
+    assert_eq!(diag.severity(), Some(Severity::Advice));
+    // this comes from <ForwardsTo as Diagnostic>::snippets()
+    check_snippets(&diag);
+}
+
+#[test]
+fn test_forward_struct_unnamed() {
+    #[derive(Debug, Diagnostic, Error)]
+    #[error("display")]
+    #[diagnostic(code(foo::bar::overridden), url("{1}"), forward(0))]
+    struct Struct(ForwardsTo, &'static str);
+
+    // Also check the From impl here
+    let diag = Struct(ForwardsTo::new(), "url here");
+    assert_eq!(diag.code().unwrap().to_string(), "foo::bar::overridden");
+    assert_eq!(diag.url().unwrap().to_string(), "url here");
+    // this comes from <ForwardsTo as Diagnostic>::snippets()
+    check_snippets(&diag);
+}
+
+#[test]
+fn test_forward_enum_named() {
+    #[derive(Debug, Diagnostic, Error)]
+    enum Enum {
+        #[error("help: {help_text}")]
+        #[diagnostic(code(foo::bar::overridden), help("{help_text}"), forward(span))]
+        Variant {
+            span: ForwardsTo,
+            help_text: &'static str,
+        },
+    }
+    // Also check the From impl here
+    let variant: Enum = Enum::Variant {
+        span: ForwardsTo::new(),
+        help_text: "overridden help please",
+    };
+    assert_eq!(variant.code().unwrap().to_string(), "foo::bar::overridden");
+    assert_eq!(
+        variant.help().unwrap().to_string(),
+        "overridden help please"
+    );
+    // this comes from <ForwardsTo as Diagnostic>::snippets()
+    check_snippets(&variant);
+}
+
+#[test]
+fn test_forward_enum_unnamed() {
+    #[derive(Debug, Diagnostic, Error)]
+    enum ForwardEnumUnnamed {
+        #[error("help: {1}")]
+        #[diagnostic(code(foo::bar::overridden), help("{1}"), forward(0))]
+        Variant(ForwardsTo, &'static str),
+    }
+    // Also check the From impl here
+    let variant = ForwardEnumUnnamed::Variant(ForwardsTo::new(), "overridden help please");
+    assert_eq!(variant.code().unwrap().to_string(), "foo::bar::overridden");
+    assert_eq!(
+        variant.help().unwrap().to_string(),
+        "overridden help please"
+    );
+    // this comes from <ForwardsTo as Diagnostic>::snippets()
     check_snippets(&variant);
 }
+
+#[test]
+fn test_unit_struct_display() {
+    #[derive(Debug, Diagnostic, Error)]
+    #[error("unit only")]
+    #[diagnostic(code(foo::bar::overridden), help("hello from unit help"))]
+    struct UnitOnly;
+    assert_eq!(UnitOnly.help().unwrap().to_string(), "hello from unit help")
+}
+
+#[test]
+fn test_unit_enum_display() {
+    #[derive(Debug, Diagnostic, Error)]
+    enum Enum {
+        #[error("unit only")]
+        #[diagnostic(code(foo::bar::overridden), help("hello from unit help"))]
+        UnitVariant,
+    }
+    assert_eq!(
+        Enum::UnitVariant.help().unwrap().to_string(),
+        "hello from unit help"
+    )
+}
diff --git a/tests/printer.rs b/tests/printer.rs
index 0ab0e73..046a768 100644
--- a/tests/printer.rs
+++ b/tests/printer.rs
@@ -196,7 +196,6 @@ fn single_line_highlight_no_label() -> Result<(), MietteError> {
     Ok(())
 }
 
-
 #[test]
 fn single_line_highlight_at_line_start() -> Result<(), MietteError> {
     #[derive(Debug, Diagnostic, Error)]
@@ -234,8 +233,8 @@ fn single_line_highlight_at_line_start() -> Result<(), MietteError> {
 
     ‽ try doing it better next time?
 "#
-        .trim_start()
-        .to_string();
+    .trim_start()
+    .to_string();
     assert_eq!(expected, out);
     Ok(())
 }