From cc03f824a58c4f8b17f0481bd259d0bf6a1af6f9 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Fri, 14 Feb 2025 14:25:03 +0100 Subject: [PATCH 01/13] change args parse method --- src/enum_derive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enum_derive.rs b/src/enum_derive.rs index dd85f65..bd22818 100644 --- a/src/enum_derive.rs +++ b/src/enum_derive.rs @@ -180,7 +180,7 @@ struct Args { impl Parse for Args { fn parse(input: ParseStream<'_>) -> Result { fn to_trimmed_string(p: &Path) -> String { - p.to_token_stream().to_string().replace(' ', "") + p.to_token_stream().to_string().replace(' ', "").split('<').next().unwrap().to_owned() } let mut inner = vec![]; From 72f14d063116a8e6dfb85ff02e6b6a4c4d977515 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Fri, 14 Feb 2025 13:54:07 +0100 Subject: [PATCH 02/13] Add support for `Into` derive --- Cargo.toml | 2 +- src/auto_enum/type_analysis.rs | 1 + src/derive/core/convert.rs | 39 ++++++++++++++++++++++++++++++++++ src/enum_derive.rs | 13 +++++++++++- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8a25ee5..21974b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ transpose_methods = [] std = [] # Enable to use `[std|core]::ops`'s `Deref`, `DerefMut`, `Index`, `IndexMut`, and `RangeBounds` traits. ops = [] -# Enable to use `[std|core]::convert`'s `AsRef` and `AsMut` traits. +# Enable to use `[std|core]::convert`'s `AsRef`, `AsMut`, `Into` traits. convert = [] # Enable to use `[std|core]::fmt`'s traits other than `Debug`, `Display` and `Write` fmt = [] diff --git a/src/auto_enum/type_analysis.rs b/src/auto_enum/type_analysis.rs index 7948b02..a5a2fe8 100644 --- a/src/auto_enum/type_analysis.rs +++ b/src/auto_enum/type_analysis.rs @@ -51,6 +51,7 @@ const TRAITS: &[&str] = &[ // core "AsRef", "AsMut", + "Into", "Debug", "fmt::Debug", "Display", diff --git a/src/derive/core/convert.rs b/src/derive/core/convert.rs index e65d169..be2d14c 100644 --- a/src/derive/core/convert.rs +++ b/src/derive/core/convert.rs @@ -29,3 +29,42 @@ pub(crate) mod as_mut { })) } } + +pub(crate) mod into { + use syn::{spanned::Spanned as _, Error, PathArguments}; + + use crate::derive::prelude::*; + + pub(crate) const NAME: &[&str] = &["Into"]; + + pub(crate) fn derive(cx: &Context, data: &Data) -> Result { + let Some(path) = cx.trait_path() else { unreachable!() }; + let Some(trait_name) = path.segments.last() else { unreachable!() }; + + let PathArguments::AngleBracketed(ref into_type) = trait_name.arguments else { + return Err(Error::new( + path.span(), + "Into trait requires a generic argument, eg: Into.", + )); + }; + if into_type.args.len() != 1 { + return Err(Error::new(into_type.span(), "Into trait must take one argument.")); + } + let target = into_type.args.first().unwrap().clone(); + let path = path.clone(); + + let mut enum_impl = derive_utils::EnumImpl::new(data); + enum_impl.set_trait(path.clone()); + for v in &data.variants { + let variant_name = &v.ident; + enum_impl.push_where_predicate(parse_quote! { + #variant_name: #path + }); + } + enum_impl.push_method(parse_quote! { + #[inline] + fn into(self) -> #target; + }); + Ok(enum_impl.build()) + } +} diff --git a/src/enum_derive.rs b/src/enum_derive.rs index bd22818..3416336 100644 --- a/src/enum_derive.rs +++ b/src/enum_derive.rs @@ -18,12 +18,20 @@ pub(crate) fn attribute(args: TokenStream, input: TokenStream) -> TokenStream { #[derive(Default)] pub(crate) struct DeriveContext { needs_pin_projection: Cell, + trait_path: Option, } impl DeriveContext { pub(crate) fn needs_pin_projection(&self) { self.needs_pin_projection.set(true); } + pub(crate) fn set_trait_path(&mut self, trait_path: Option) { + self.trait_path = trait_path; + } + + pub(crate) fn trait_path(&self) -> Option<&Path> { + self.trait_path.as_ref() + } } type DeriveFn = fn(&'_ DeriveContext, &'_ Data) -> Result; @@ -46,6 +54,8 @@ fn get_derive(s: &str) -> Option { core::convert::as_mut, #[cfg(feature = "convert")] core::convert::as_ref, + #[cfg(feature = "convert")] + core::convert::into, core::fmt::debug, core::fmt::display, #[cfg(feature = "fmt")] @@ -279,10 +289,11 @@ fn expand(args: TokenStream, input: TokenStream) -> Result { let mut derive = vec![]; let mut items = TokenStream::new(); - let cx = DeriveContext::default(); + let mut cx = DeriveContext::default(); for (s, arg) in args { match (get_derive(s), arg) { (Some(f), _) => { + cx.set_trait_path(arg.cloned()); items.extend( f(&cx, &data).map_err(|e| format_err!(data, "`enum_derive({})` {}", s, e))?, ); From 43c88a254e31aafe64a0b7f21794ecbf6ac54f07 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Fri, 14 Feb 2025 14:01:36 +0100 Subject: [PATCH 03/13] add tests --- tests/ui/auto_enum/args.rs | 24 +++++++++++ tests/ui/auto_enum/args.stderr | 75 ++++++++++++++++++++++++++++------ 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/tests/ui/auto_enum/args.rs b/tests/ui/auto_enum/args.rs index f468f2a..4b47e9b 100644 --- a/tests/ui/auto_enum/args.rs +++ b/tests/ui/auto_enum/args.rs @@ -18,6 +18,30 @@ fn unexpected_token_2(x: usize) -> impl Iterator { } } +#[auto_enum(Into)] //~ ERROR missing Into generic argument +fn missing_into_arg(x: usize) -> impl Into { + match x { + 0 => 8, + _ => 2, + } +} + +#[auto_enum(Into)] //~ ERROR too many Into generic arguments +fn too_many_into_arg(x: usize) -> impl Into { + match x { + 0 => 8, + _ => 2, + } +} + +#[auto_enum(Into)] //~ ERROR Into generic arg unexpected token +fn into_arg_unexpected_token(x: usize) -> impl Into { + match x { + 0 => 8, + _ => 2, + } +} + mod marker { use auto_enums::auto_enum; diff --git a/tests/ui/auto_enum/args.stderr b/tests/ui/auto_enum/args.stderr index 8467627..b41b6b9 100644 --- a/tests/ui/auto_enum/args.stderr +++ b/tests/ui/auto_enum/args.stderr @@ -10,38 +10,89 @@ error: expected identifier 13 | #[auto_enum(Iterator,;)] //~ ERROR expected identifier | ^ +error: `enum_derive(Into)` Into trait requires a generic argument, eg: Into. + --> tests/ui/auto_enum/args.rs:21:1 + | +21 | #[auto_enum(Into)] //~ ERROR missing Into generic argument + | ^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `enum_derive(Into)` Into trait must take one argument. + --> tests/ui/auto_enum/args.rs:29:1 + | +29 | #[auto_enum(Into)] //~ ERROR too many Into generic arguments + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `enum_derive(Into)` Into trait requires a generic argument, eg: Into. + --> tests/ui/auto_enum/args.rs:37:1 + | +37 | #[auto_enum(Into)] //~ ERROR Into generic arg unexpected token + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) + error: expected `,` - --> tests/ui/auto_enum/args.rs:24:23 + --> tests/ui/auto_enum/args.rs:48:23 | -24 | #[auto_enum(marker{f}, Iterator)] //~ ERROR expected `,` +48 | #[auto_enum(marker{f}, Iterator)] //~ ERROR expected `,` | ^ error: expected `,` - --> tests/ui/auto_enum/args.rs:32:23 + --> tests/ui/auto_enum/args.rs:56:23 | -32 | #[auto_enum(marker[f], Iterator)] //~ ERROR expected `,` +56 | #[auto_enum(marker[f], Iterator)] //~ ERROR expected `,` | ^ error: expected `,` - --> tests/ui/auto_enum/args.rs:40:23 + --> tests/ui/auto_enum/args.rs:64:23 | -40 | #[auto_enum(marker(f), Iterator)] //~ ERROR expected `,` +64 | #[auto_enum(marker(f), Iterator)] //~ ERROR expected `,` | ^ error: duplicate `marker` argument - --> tests/ui/auto_enum/args.rs:48:29 + --> tests/ui/auto_enum/args.rs:72:29 | -48 | #[auto_enum(marker = f, marker = g, Iterator)] //~ ERROR duplicate `marker` argument +72 | #[auto_enum(marker = f, marker = g, Iterator)] //~ ERROR duplicate `marker` argument | ^^^^^^ error: expected identifier - --> tests/ui/auto_enum/args.rs:56:25 + --> tests/ui/auto_enum/args.rs:80:25 | -56 | #[auto_enum(marker =, Iterator)] //~ ERROR expected identifier +80 | #[auto_enum(marker =, Iterator)] //~ ERROR expected identifier | ^ error: expected `,` - --> tests/ui/auto_enum/args.rs:64:28 + --> tests/ui/auto_enum/args.rs:88:28 | -64 | #[auto_enum(marker = f t, Iterator)] //~ ERROR expected `,` +88 | #[auto_enum(marker = f t, Iterator)] //~ ERROR expected `,` | ^ + +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `__Enum2568906583121684409` + --> tests/ui/auto_enum/args.rs:21:1 + | +21 | #[auto_enum(Into)] //~ ERROR missing Into generic argument + | ^^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `__Enum2568906583121684409` + | + = help: if you wanted to use a crate named `__Enum2568906583121684409`, use `cargo add __Enum2568906583121684409` to add it to your `Cargo.toml` + = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `__Enum15377793773749478612` + --> tests/ui/auto_enum/args.rs:29:1 + | +29 | #[auto_enum(Into)] //~ ERROR too many Into generic arguments + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `__Enum15377793773749478612` + | + = help: if you wanted to use a crate named `__Enum15377793773749478612`, use `cargo add __Enum15377793773749478612` to add it to your `Cargo.toml` + = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `__Enum12908244860424601373` + --> tests/ui/auto_enum/args.rs:37:1 + | +37 | #[auto_enum(Into)] //~ ERROR Into generic arg unexpected token + | ^^^^^^^^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `__Enum12908244860424601373` + | + = help: if you wanted to use a crate named `__Enum12908244860424601373`, use `cargo add __Enum12908244860424601373` to add it to your `Cargo.toml` + = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) From a605b76e2352081a99cf8a7748077abfd92e2984 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Fri, 14 Feb 2025 14:16:57 +0100 Subject: [PATCH 04/13] remove let-else statements --- src/derive/core/convert.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/derive/core/convert.rs b/src/derive/core/convert.rs index be2d14c..968ae9c 100644 --- a/src/derive/core/convert.rs +++ b/src/derive/core/convert.rs @@ -38,19 +38,23 @@ pub(crate) mod into { pub(crate) const NAME: &[&str] = &["Into"]; pub(crate) fn derive(cx: &Context, data: &Data) -> Result { - let Some(path) = cx.trait_path() else { unreachable!() }; - let Some(trait_name) = path.segments.last() else { unreachable!() }; - - let PathArguments::AngleBracketed(ref into_type) = trait_name.arguments else { - return Err(Error::new( - path.span(), - "Into trait requires a generic argument, eg: Into.", - )); + let path = cx.trait_path().unwrap_or_else(|| unreachable!()); + let trait_name = path.segments.last().unwrap_or_else(|| unreachable!()); + let into_type_generics = match trait_name.arguments { + PathArguments::AngleBracketed(ref generics) => generics, + _ => { + return Err(Error::new( + path.span(), + "Into trait requires a generic argument, eg: Into.", + )) + } }; - if into_type.args.len() != 1 { - return Err(Error::new(into_type.span(), "Into trait must take one argument.")); + + if into_type_generics.args.len() != 1 { + return Err(Error::new(into_type_generics.span(), "Into trait must take one argument.")); } - let target = into_type.args.first().unwrap().clone(); + + let target = into_type_generics.args.first().unwrap().clone(); let path = path.clone(); let mut enum_impl = derive_utils::EnumImpl::new(data); From e3ac533c62111c8a758d4509123f088442a315da Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Fri, 14 Feb 2025 15:46:30 +0100 Subject: [PATCH 05/13] fix clippy --- src/enum_derive.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/enum_derive.rs b/src/enum_derive.rs index 3416336..a21a104 100644 --- a/src/enum_derive.rs +++ b/src/enum_derive.rs @@ -29,6 +29,7 @@ impl DeriveContext { self.trait_path = trait_path; } + #[allow(dead_code)] // only used for `Into` derive pub(crate) fn trait_path(&self) -> Option<&Path> { self.trait_path.as_ref() } From e18d22a2d7d6a2348c31542d3b6d6531a84a8150 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Fri, 14 Feb 2025 15:51:05 +0100 Subject: [PATCH 06/13] fmt --- src/derive/core/convert.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/derive/core/convert.rs b/src/derive/core/convert.rs index 968ae9c..03c3cd8 100644 --- a/src/derive/core/convert.rs +++ b/src/derive/core/convert.rs @@ -51,7 +51,10 @@ pub(crate) mod into { }; if into_type_generics.args.len() != 1 { - return Err(Error::new(into_type_generics.span(), "Into trait must take one argument.")); + return Err(Error::new( + into_type_generics.span(), + "Into trait must take one argument.", + )); } let target = into_type_generics.args.first().unwrap().clone(); From be826aa24f292b5c7d1b6b6123e9533e1a8b4074 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Sat, 15 Feb 2025 00:03:00 +0100 Subject: [PATCH 07/13] add hard error for Into without proper feature --- src/enum_derive.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/enum_derive.rs b/src/enum_derive.rs index a21a104..0d26cd4 100644 --- a/src/enum_derive.rs +++ b/src/enum_derive.rs @@ -292,6 +292,14 @@ fn expand(args: TokenStream, input: TokenStream) -> Result { let mut items = TokenStream::new(); let mut cx = DeriveContext::default(); for (s, arg) in args { + #[cfg(not(feature = "convert"))] + if s == "Into" { + return Err(Error::new( + proc_macro2::Span::call_site(), + "`Into` derive is only supported via `convert` feature.", + )); + } + match (get_derive(s), arg) { (Some(f), _) => { cx.set_trait_path(arg.cloned()); From 1e79648ec5034c8f80ff29fe45758647309a081f Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:27:54 +0200 Subject: [PATCH 08/13] fmt --- src/derive/core/convert.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/derive/core/convert.rs b/src/derive/core/convert.rs index 03c3cd8..711a5b1 100644 --- a/src/derive/core/convert.rs +++ b/src/derive/core/convert.rs @@ -31,7 +31,7 @@ pub(crate) mod as_mut { } pub(crate) mod into { - use syn::{spanned::Spanned as _, Error, PathArguments}; + use syn::{Error, PathArguments, spanned::Spanned as _}; use crate::derive::prelude::*; @@ -46,7 +46,7 @@ pub(crate) mod into { return Err(Error::new( path.span(), "Into trait requires a generic argument, eg: Into.", - )) + )); } }; From e3b483ca9c3362b655390b8c2d4e65d44db5a838 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:34:50 +0200 Subject: [PATCH 09/13] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 023e65c..1e7b4ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com ## [Unreleased] +- Add `Into` derive implementation ([#164](https://github.com/taiki-e/auto_enums/pull/164)). + ## [0.8.7] - 2025-01-16 - Update `derive_utils` to 0.15. This uses `#[automatically_derived]` on generated impls to improve coverage support. From 8748b3004cb80112b57fd59032d5a2dc595060f7 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Mon, 29 Sep 2025 18:14:28 +0200 Subject: [PATCH 10/13] replace err block with todo --- src/enum_derive.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/enum_derive.rs b/src/enum_derive.rs index 0d26cd4..9bd4987 100644 --- a/src/enum_derive.rs +++ b/src/enum_derive.rs @@ -292,14 +292,7 @@ fn expand(args: TokenStream, input: TokenStream) -> Result { let mut items = TokenStream::new(); let mut cx = DeriveContext::default(); for (s, arg) in args { - #[cfg(not(feature = "convert"))] - if s == "Into" { - return Err(Error::new( - proc_macro2::Span::call_site(), - "`Into` derive is only supported via `convert` feature.", - )); - } - + // TODO: add error message "`...` derive is only supported via `...` feature." match (get_derive(s), arg) { (Some(f), _) => { cx.set_trait_path(arg.cloned()); From 0d9c6ba2f84ff9f751826e99006917d394d89081 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Mon, 29 Sep 2025 18:51:39 +0200 Subject: [PATCH 11/13] move tests --- tests/ui/auto_enum/args.rs | 24 ---------- tests/ui/auto_enum/args.stderr | 75 +++++--------------------------- tests/ui/enum_derive/args.rs | 11 +++++ tests/ui/enum_derive/args.stderr | 18 ++++++++ 4 files changed, 41 insertions(+), 87 deletions(-) diff --git a/tests/ui/auto_enum/args.rs b/tests/ui/auto_enum/args.rs index 4b47e9b..f468f2a 100644 --- a/tests/ui/auto_enum/args.rs +++ b/tests/ui/auto_enum/args.rs @@ -18,30 +18,6 @@ fn unexpected_token_2(x: usize) -> impl Iterator { } } -#[auto_enum(Into)] //~ ERROR missing Into generic argument -fn missing_into_arg(x: usize) -> impl Into { - match x { - 0 => 8, - _ => 2, - } -} - -#[auto_enum(Into)] //~ ERROR too many Into generic arguments -fn too_many_into_arg(x: usize) -> impl Into { - match x { - 0 => 8, - _ => 2, - } -} - -#[auto_enum(Into)] //~ ERROR Into generic arg unexpected token -fn into_arg_unexpected_token(x: usize) -> impl Into { - match x { - 0 => 8, - _ => 2, - } -} - mod marker { use auto_enums::auto_enum; diff --git a/tests/ui/auto_enum/args.stderr b/tests/ui/auto_enum/args.stderr index b41b6b9..8467627 100644 --- a/tests/ui/auto_enum/args.stderr +++ b/tests/ui/auto_enum/args.stderr @@ -10,89 +10,38 @@ error: expected identifier 13 | #[auto_enum(Iterator,;)] //~ ERROR expected identifier | ^ -error: `enum_derive(Into)` Into trait requires a generic argument, eg: Into. - --> tests/ui/auto_enum/args.rs:21:1 - | -21 | #[auto_enum(Into)] //~ ERROR missing Into generic argument - | ^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `enum_derive(Into)` Into trait must take one argument. - --> tests/ui/auto_enum/args.rs:29:1 - | -29 | #[auto_enum(Into)] //~ ERROR too many Into generic arguments - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `enum_derive(Into)` Into trait requires a generic argument, eg: Into. - --> tests/ui/auto_enum/args.rs:37:1 - | -37 | #[auto_enum(Into)] //~ ERROR Into generic arg unexpected token - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) - error: expected `,` - --> tests/ui/auto_enum/args.rs:48:23 + --> tests/ui/auto_enum/args.rs:24:23 | -48 | #[auto_enum(marker{f}, Iterator)] //~ ERROR expected `,` +24 | #[auto_enum(marker{f}, Iterator)] //~ ERROR expected `,` | ^ error: expected `,` - --> tests/ui/auto_enum/args.rs:56:23 + --> tests/ui/auto_enum/args.rs:32:23 | -56 | #[auto_enum(marker[f], Iterator)] //~ ERROR expected `,` +32 | #[auto_enum(marker[f], Iterator)] //~ ERROR expected `,` | ^ error: expected `,` - --> tests/ui/auto_enum/args.rs:64:23 + --> tests/ui/auto_enum/args.rs:40:23 | -64 | #[auto_enum(marker(f), Iterator)] //~ ERROR expected `,` +40 | #[auto_enum(marker(f), Iterator)] //~ ERROR expected `,` | ^ error: duplicate `marker` argument - --> tests/ui/auto_enum/args.rs:72:29 + --> tests/ui/auto_enum/args.rs:48:29 | -72 | #[auto_enum(marker = f, marker = g, Iterator)] //~ ERROR duplicate `marker` argument +48 | #[auto_enum(marker = f, marker = g, Iterator)] //~ ERROR duplicate `marker` argument | ^^^^^^ error: expected identifier - --> tests/ui/auto_enum/args.rs:80:25 + --> tests/ui/auto_enum/args.rs:56:25 | -80 | #[auto_enum(marker =, Iterator)] //~ ERROR expected identifier +56 | #[auto_enum(marker =, Iterator)] //~ ERROR expected identifier | ^ error: expected `,` - --> tests/ui/auto_enum/args.rs:88:28 + --> tests/ui/auto_enum/args.rs:64:28 | -88 | #[auto_enum(marker = f t, Iterator)] //~ ERROR expected `,` +64 | #[auto_enum(marker = f t, Iterator)] //~ ERROR expected `,` | ^ - -error[E0433]: failed to resolve: use of unresolved module or unlinked crate `__Enum2568906583121684409` - --> tests/ui/auto_enum/args.rs:21:1 - | -21 | #[auto_enum(Into)] //~ ERROR missing Into generic argument - | ^^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `__Enum2568906583121684409` - | - = help: if you wanted to use a crate named `__Enum2568906583121684409`, use `cargo add __Enum2568906583121684409` to add it to your `Cargo.toml` - = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0433]: failed to resolve: use of unresolved module or unlinked crate `__Enum15377793773749478612` - --> tests/ui/auto_enum/args.rs:29:1 - | -29 | #[auto_enum(Into)] //~ ERROR too many Into generic arguments - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `__Enum15377793773749478612` - | - = help: if you wanted to use a crate named `__Enum15377793773749478612`, use `cargo add __Enum15377793773749478612` to add it to your `Cargo.toml` - = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0433]: failed to resolve: use of unresolved module or unlinked crate `__Enum12908244860424601373` - --> tests/ui/auto_enum/args.rs:37:1 - | -37 | #[auto_enum(Into)] //~ ERROR Into generic arg unexpected token - | ^^^^^^^^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `__Enum12908244860424601373` - | - = help: if you wanted to use a crate named `__Enum12908244860424601373`, use `cargo add __Enum12908244860424601373` to add it to your `Cargo.toml` - = note: this error originates in the attribute macro `auto_enum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/enum_derive/args.rs b/tests/ui/enum_derive/args.rs index 6b9e17c..ce62127 100644 --- a/tests/ui/enum_derive/args.rs +++ b/tests/ui/enum_derive/args.rs @@ -26,4 +26,15 @@ enum Enum4 { B(B), } +#[enum_derive(Into)] //~ ERROR missing Into generic argument +enum Enum5 { + A(A), + B(B), +} +#[enum_derive(Into)] //~ ERROR too many Into generic arguments +enum Enum6 { + A(A), + B(B), +} + fn main() {} diff --git a/tests/ui/enum_derive/args.stderr b/tests/ui/enum_derive/args.stderr index fc5edd0..9e7440c 100644 --- a/tests/ui/enum_derive/args.stderr +++ b/tests/ui/enum_derive/args.stderr @@ -21,3 +21,21 @@ error: expected `,` | 23 | #[enum_derive(Clone Foo)] //~ ERROR expected `,` | ^^^ + +error: `enum_derive(Into)` Into trait requires a generic argument, eg: Into. + --> tests/ui/enum_derive/args.rs:30:1 + | +30 | / enum Enum5 { +31 | | A(A), +32 | | B(B), +33 | | } + | |_^ + +error: `enum_derive(Into)` Into trait must take one argument. + --> tests/ui/enum_derive/args.rs:35:1 + | +35 | / enum Enum6 { +36 | | A(A), +37 | | B(B), +38 | | } + | |_^ From 52e961c3c2cef4fb05b006017c89323f14511210 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Wed, 1 Oct 2025 16:02:14 +0200 Subject: [PATCH 12/13] missing passing test --- tests/auto_enum.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/auto_enum.rs b/tests/auto_enum.rs index 3807084..bfe11fc 100644 --- a/tests/auto_enum.rs +++ b/tests/auto_enum.rs @@ -490,6 +490,25 @@ fn marker() { assert_eq!(marker6(10).sum::(), 3); } +#[cfg(feature = "convert")] +#[test] +fn into() { + #[auto_enum(Into)] + fn number(x: u8) -> impl Into { + match x { + 0 => 1_u8, + 1 => 1_u16, + 2 => 1_u32, + 3 => 1_i8, + 4 => 1_i16, + 5 => 1_i32, + 6 => 1_i64, + _ => true, + } + } + assert_eq!(number(2).into(), 1_i64); +} + #[cfg(feature = "transpose_methods")] #[cfg(feature = "std")] #[test] From 232d02639f67238281f92de88a1c0121213a02c2 Mon Sep 17 00:00:00 2001 From: vic1707 <28602203+vic1707@users.noreply.github.com> Date: Wed, 1 Oct 2025 22:43:26 +0200 Subject: [PATCH 13/13] test fix type_analysis --- src/auto_enum/type_analysis.rs | 14 +++++++++----- src/derive/core/convert.rs | 13 +++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/auto_enum/type_analysis.rs b/src/auto_enum/type_analysis.rs index a5a2fe8..8aedede 100644 --- a/src/auto_enum/type_analysis.rs +++ b/src/auto_enum/type_analysis.rs @@ -20,12 +20,16 @@ pub(super) fn collect_impl_trait(args: &[Path], traits: &mut Vec, ty: &mut visit_mut::visit_type_impl_trait_mut(self, node); for ty in &node.bounds { - if let TypeParamBound::Trait(ty) = ty { - let ty = path(ty.path.segments.iter().map(|ty| ty.ident.clone().into())); + if let TypeParamBound::Trait(orig_ty) = ty { + let ty = path(orig_ty.path.segments.iter().map(|ty| ty.ident.clone().into())); let ty_str = ty.to_token_stream().to_string(); - let ty_trimmed = ty_str.replace(' ', ""); - if TRAITS.contains(&&*ty_trimmed) - && !self.args.iter().any(|x| x.to_token_stream().to_string() == ty_str) + let orig_ty_str = orig_ty.to_token_stream().to_string(); + if TRAITS.contains(&&*ty_str) + && !self.args.iter().any(|x| { + let arg_str = x.to_token_stream().to_string(); + // Some derives (ie: Into) need to check against the derive argument itself + arg_str == ty_str || arg_str == orig_ty_str + }) { self.has_impl_trait = true; self.traits.push(ty); diff --git a/src/derive/core/convert.rs b/src/derive/core/convert.rs index 711a5b1..969c653 100644 --- a/src/derive/core/convert.rs +++ b/src/derive/core/convert.rs @@ -40,14 +40,11 @@ pub(crate) mod into { pub(crate) fn derive(cx: &Context, data: &Data) -> Result { let path = cx.trait_path().unwrap_or_else(|| unreachable!()); let trait_name = path.segments.last().unwrap_or_else(|| unreachable!()); - let into_type_generics = match trait_name.arguments { - PathArguments::AngleBracketed(ref generics) => generics, - _ => { - return Err(Error::new( - path.span(), - "Into trait requires a generic argument, eg: Into.", - )); - } + let PathArguments::AngleBracketed(ref into_type_generics) = trait_name.arguments else { + return Err(Error::new( + path.span(), + "Into trait requires a generic argument, eg: Into.", + )); }; if into_type_generics.args.len() != 1 {