diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ff808f3..0d5b0a5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -36,7 +36,7 @@ jobs: rust-version: nightly - name: Generate Docs (reference docs.rs) run: | - cargo rustdoc -- --cfg docsrs -Z unstable-options $(cargo metadata --format-version 1 | jq --raw-output '.packages | map("--extern-html-root-url=\(.name)=https://docs.rs/\(.name)/\(.version)") | join(" ")') + cargo rustdoc --all-features -- --cfg docsrs -Z unstable-options $(cargo metadata --format-version 1 | jq --raw-output '.packages | map("--extern-html-root-url=\(.name)=https://docs.rs/\(.name)/\(.version)") | join(" ")') - uses: actions/upload-pages-artifact@v5 with: path: 'target/doc' diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 587e9da..ef5c08a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -34,14 +34,14 @@ jobs: - uses: hecrj/setup-rust-action@v1 with: rust-version: ${{ matrix.rust }} - - uses: bruxisma/setup-cargo-hack@v1 + - uses: baptiste0928/cargo-install@v3 with: - cargo-hack-version: "0.5" + crate: cargo-hack - name: Build - run: cargo hack build --feature-powerset ${{ matrix.cargo_flags }} + run: cargo hack build --feature-powerset --mutually-exclusive-features=syn2,syn3 ${{ matrix.cargo_flags }} - name: Test - run: cargo hack test --feature-powerset --all-targets --no-fail-fast --workspace + run: cargo hack test --feature-powerset --mutually-exclusive-features=syn2,syn3 --all-targets --no-fail-fast --workspace - name: Doc Test - run: cargo test --all-features --doc --no-fail-fast --workspace + run: cargo test --features=darling --doc --no-fail-fast --workspace - name: Build Docs run: cargo doc --all-features --workspace diff --git a/Cargo.toml b/Cargo.toml index 4a0b121..791e52f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,17 +20,18 @@ proc-macro2 = "1.0.60" quote = "1" syn1 = { package = "syn", version = "1", default-features = false, optional = true, features = ["printing"] } syn2 = { package = "syn", version = "2", default-features = false, optional = true, features = ["printing", "parsing"] } +syn3 = { package = "syn", version = "3", default-features = false, optional = true, features = ["printing", "parsing"] } darling_core = { version = "0.23.0", optional = true } [features] default = ["syn", "macros"] -syn = ["syn2"] +syn = ["syn3"] darling = ["darling_core"] [dev-dependencies] proc-macro-utils = "0.10.0" proc-macro2 = { version = "1", features = ["span-locations"] } -syn2 = {package = "syn", version = "2", features = ["full"]} +syn3 = { package = "syn", version = "3", features = ["full"] } [package.metadata.docs.rs] all-features = true diff --git a/examples/macro/Cargo.toml b/examples/macro/Cargo.toml index ddba6f3..919d73e 100644 --- a/examples/macro/Cargo.toml +++ b/examples/macro/Cargo.toml @@ -11,7 +11,7 @@ proc-macro = true manyhow = {path = "../..", default-features = false, features = ["macros", "syn"]} proc-macro2 = "1" quote = "1" -syn = { version = "2", features = ["full"] } +syn = { version = "3", features = ["full"] } [dev-dependencies] trybuild = "1.0.111" diff --git a/examples/macro/src/lib.rs b/examples/macro/src/lib.rs index 27fc027..73b0b6c 100644 --- a/examples/macro/src/lib.rs +++ b/examples/macro/src/lib.rs @@ -1,4 +1,4 @@ -use manyhow::{bail, manyhow, Emitter, ErrorMessage, Result, SilentError}; +use manyhow::{Emitter, ErrorMessage, Result, SilentError, bail, manyhow}; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; diff --git a/examples/no_macro/Cargo.toml b/examples/no_macro/Cargo.toml index d013aad..31645b7 100644 --- a/examples/no_macro/Cargo.toml +++ b/examples/no_macro/Cargo.toml @@ -11,7 +11,7 @@ proc-macro = true manyhow = { path = "../..", default-features = false, features = ["syn"] } proc-macro2 = "1" quote = "1" -syn = { version = "2", features = ["full"] } +syn = { version = "3", features = ["full"] } [dev-dependencies] trybuild = "1.0.111" diff --git a/examples/no_macro/src/lib.rs b/examples/no_macro/src/lib.rs index 2abe927..01bc3ab 100644 --- a/examples/no_macro/src/lib.rs +++ b/examples/no_macro/src/lib.rs @@ -1,4 +1,4 @@ -use manyhow::{attribute, bail, derive, function, Emitter, ErrorMessage, Result, SilentError}; +use manyhow::{Emitter, ErrorMessage, Result, SilentError, attribute, bail, derive, function}; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 477e6bc..755b003 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,9 +1,9 @@ use std::fmt::{Display, Write}; use std::mem; -use proc_macro2::{Group, Ident, Span, TokenStream, TokenTree}; use proc_macro_utils::{Delimited, TokenStream2Ext, TokenStreamExt, TokenTree2Ext, TokenTreePunct}; -use quote::{format_ident, quote, quote_spanned, ToTokens}; +use proc_macro2::{Group, Ident, Span, TokenStream, TokenTree}; +use quote::{ToTokens, format_ident, quote, quote_spanned}; #[derive(PartialEq, Eq, Clone, Copy)] enum ProcMacroType { diff --git a/src/error.rs b/src/error.rs index 73c1b7b..4ed8e22 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,6 +12,8 @@ use quote::{ToTokens, quote_spanned}; use syn1::Error as Syn1Error; #[cfg(feature = "syn2")] use syn2::Error as Syn2Error; +#[cfg(feature = "syn3")] +use syn3::Error as Syn3Error; #[cfg(doc)] use crate::MacroOutput; @@ -41,6 +43,12 @@ impl From for Error { Self::from(error) } } +#[cfg(feature = "syn3")] +impl From for Error { + fn from(error: Syn3Error) -> Self { + Self::from(error) + } +} #[cfg(feature = "darling")] impl From for Error { fn from(error: DarlingError) -> Self { @@ -163,6 +171,12 @@ impl From for Syn2Error { Self::new_spanned(value.to_token_stream(), value) } } +#[cfg(feature = "syn3")] +impl From for Syn3Error { + fn from(value: ErrorMessage) -> Self { + Self::new_spanned(value.to_token_stream(), value) + } +} impl Add for ErrorMessage { type Output = Error; @@ -391,12 +405,18 @@ impl ToTokensError for Syn1Error { self.to_compile_error().to_tokens(tokens); } } -#[cfg(feature = "syn")] +#[cfg(feature = "syn2")] impl ToTokensError for Syn2Error { fn to_tokens(&self, tokens: &mut TokenStream) { self.to_compile_error().to_tokens(tokens); } } +#[cfg(feature = "syn3")] +impl ToTokensError for Syn3Error { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.to_compile_error().to_tokens(tokens); + } +} #[cfg(feature = "darling")] impl ToTokensError for DarlingError { fn to_tokens(&self, tokens: &mut TokenStream) { diff --git a/src/lib.rs b/src/lib.rs index 491ecdc..9ea2fc8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ //! ``` //! # use proc_macro2::TokenStream; //! # use quote::quote; -//! # use syn2 as syn; +//! # use syn3 as syn; //! use proc_macro2::TokenStream as TokenStream2; //! //! # let _ = quote!{ @@ -41,7 +41,7 @@ //! //! ``` //! # use quote::quote; -//! # use syn2 as syn; +//! # use syn3 as syn; //! use manyhow::manyhow; //! use proc_macro2::TokenStream as TokenStream2; //! @@ -79,7 +79,7 @@ //! //! mod module { //! # use quote::quote; -//! # use syn2 as syn; +//! # use syn3 as syn; //! use proc_macro2::TokenStream as TokenStream2; //! //! pub fn my_macro(input: TokenStream2) -> syn::Result { @@ -150,7 +150,7 @@ //! ``` //! # use proc_macro2::TokenStream; //! # use quote::quote; -//! # use syn2 as syn; +//! # use syn3 as syn; //! use proc_macro2::TokenStream as TokenStream2; //! //! # let _ = quote!{ @@ -195,8 +195,8 @@ //! //! ``` //! # use quote::quote; -//! # use syn2 as syn; -//! use manyhow::{manyhow, Emitter, ErrorMessage}; +//! # use syn3 as syn; +//! use manyhow::{Emitter, ErrorMessage, manyhow}; //! use proc_macro2::TokenStream as TokenStream2; //! //! # let _ = quote!{ @@ -224,7 +224,8 @@ //! //! - `macros` **default** Enables [`#[manyhow]`](macros::manyhow) attribute //! macro. -//! - `syn`/`syn2` **default** Enables errors for [`syn` 2.x](https://docs.rs/syn/latest/syn/). +//! - `syn`/`syn3` **default** Enables errors for [`syn` 3.x](https://docs.rs/syn/latest/syn/). +//! - `syn2` **default** Enables errors for [`syn` 2.x](https://docs.rs/syn/2.0.119/syn/). //! - `syn1` Enables errors for [`syn` 1.x](https://docs.rs/syn/1.0.109/syn/index.html). //! - `darling` Enables errors for [`darling`](https://docs.rs/darling/latest/index.html). @@ -232,13 +233,13 @@ pub use macros::manyhow; use proc_macro2::TokenStream; #[cfg(doc)] -use {quote::ToTokens, syn2::parse::Parse}; +use {quote::ToTokens, syn3::parse::Parse}; extern crate proc_macro; #[macro_use] mod span_ranged; -pub use span_ranged::{to_tokens_span_range, SpanRanged}; +pub use span_ranged::{SpanRanged, to_tokens_span_range}; #[macro_use] mod macro_rules; mod error; @@ -318,7 +319,7 @@ macro_rules! __macro_handler { /// ``` /// # use proc_macro_utils::assert_tokens; /// # use quote::{quote, ToTokens}; -/// use manyhow::{attribute, Emitter, Result}; +/// use manyhow::{Emitter, Result, attribute}; /// use proc_macro2::TokenStream; /// # let input = quote!(); /// # let item = quote!(); @@ -342,9 +343,9 @@ macro_rules! __macro_handler { /// initialized with `item`. To override assign a new `TokenStream`: /// ``` /// # use proc_macro_utils::assert_tokens; -/// use manyhow::{attribute, Result, SilentError}; +/// use manyhow::{Result, SilentError, attribute}; /// use proc_macro2::TokenStream; -/// use quote::{quote, ToTokens}; +/// use quote::{ToTokens, quote}; /// # let input = quote!(input); /// let item = quote!( /// struct Struct; @@ -429,7 +430,7 @@ pub fn attribute< /// ``` /// # use proc_macro_utils::assert_tokens; /// # use quote::{quote, ToTokens}; -/// use manyhow::{attribute, Emitter, Result}; +/// use manyhow::{Emitter, Result, attribute}; /// use proc_macro2::TokenStream; /// # let input = quote!(); /// # let item = quote!(); @@ -448,10 +449,10 @@ pub fn attribute< /// be initialized with `item`. To override assign a new `TokenStream`: /// ``` /// # use proc_macro_utils::assert_tokens; -/// # use syn2 as syn; -/// use manyhow::{attribute, Result, SilentError}; +/// # use syn3 as syn; +/// use manyhow::{Result, SilentError, attribute}; /// use proc_macro2::TokenStream; -/// use quote::{quote, ToTokens}; +/// use quote::{ToTokens, quote}; /// # let input = quote!(input); /// let item = quote!( /// struct Struct; @@ -500,7 +501,7 @@ macro_rules! attribute { /// ``` /// # use proc_macro_utils::assert_tokens; /// # use quote::{quote, ToTokens}; -/// use manyhow::{derive, Emitter, Result}; +/// use manyhow::{Emitter, Result, derive}; /// use proc_macro2::TokenStream; /// # let item = quote!(); /// # let output: TokenStream = @@ -549,8 +550,8 @@ pub fn derive< /// ``` /// # use proc_macro_utils::assert_tokens; /// # use quote::{quote, ToTokens}; -/// # use syn2 as syn; -/// use manyhow::{derive, Emitter, Result}; +/// # use syn3 as syn; +/// use manyhow::{Emitter, Result, derive}; /// use proc_macro2::TokenStream; /// # let item = quote!(); /// # let output: TokenStream = @@ -583,7 +584,7 @@ macro_rules! derive { /// ``` /// # use proc_macro_utils::assert_tokens; /// # use quote::{quote, ToTokens}; -/// use manyhow::{function, Emitter, Result}; +/// use manyhow::{Emitter, Result, function}; /// use proc_macro2::TokenStream; /// # let input = quote!(); /// # let output: TokenStream = @@ -667,8 +668,8 @@ pub fn function< /// ``` /// # use proc_macro_utils::assert_tokens; /// # use quote::{quote, ToTokens}; -/// # use syn2 as syn; -/// use manyhow::{function, Emitter, Result}; +/// # use syn3 as syn; +/// use manyhow::{Emitter, Result, function}; /// use proc_macro2::TokenStream; /// # let input = quote!(); /// # let output: TokenStream = @@ -752,6 +753,24 @@ fn function_macro() { }); assert_eq!(output.to_string(), "hello"); } + + #[cfg(feature = "syn3")] + { + use quote::ToTokens; + let output: TokenStream = function!( + #[as_dummy] + quote!(hello;), + |input: syn3::LitInt| -> TokenStream { input.into_token_stream() } + ); + assert_eq!( + output.to_string(), + quote!(hello; ::core::compile_error! { "expected integer literal" }).to_string() + ); + let output: TokenStream = function!(quote!(20), |_input: syn3::LitInt| -> syn3::Ident { + syn3::parse_quote!(hello) + }); + assert_eq!(output.to_string(), "hello"); + } } macro_rules! macro_input { diff --git a/src/macro_rules.rs b/src/macro_rules.rs index 08eed40..1ae4293 100644 --- a/src/macro_rules.rs +++ b/src/macro_rules.rs @@ -116,7 +116,7 @@ macro_rules! error_message { /// ```should_panic /// # use manyhow::bail; /// # use proc_macro2::Span; -/// # use syn2 as syn; +/// # use syn3 as syn; /// bail!("an error message"; error = "with attachments"); /// let span = Span::call_site(); /// bail!(span, "error message"); @@ -156,7 +156,7 @@ macro_rules! bail { /// ```should_panic /// # use manyhow::ensure; /// # use proc_macro2::Span; -/// # use syn2 as syn; +/// # use syn3 as syn; /// let span = Span::call_site(); /// ensure!(false, span, "error message"); /// let error = syn::Error::new(Span::call_site(), "an error"); @@ -184,7 +184,7 @@ macro_rules! ensure { /// ``` /// # use manyhow::{emit, Emitter}; /// # use proc_macro2::Span; -/// # use syn2 as syn; +/// # use syn3 as syn; /// let mut emitter = Emitter::new(); /// emit!(emitter, "an error message"); /// emit!(emitter, "an error message"; error = "with attachments"); @@ -198,7 +198,7 @@ macro_rules! ensure { /// ``` /// # use manyhow::{emit, error_message, Error}; /// # use proc_macro2::Span; -/// # use syn2 as syn; +/// # use syn3 as syn; /// let mut error: Error = error_message!("initial error").into(); /// emit!(error, "an error message"); /// ``` @@ -207,7 +207,7 @@ macro_rules! ensure { /// ``` /// # use manyhow::emit; /// # use proc_macro2::Span; -/// # use syn2 as syn; +/// # use syn3 as syn; /// let mut errors = Vec::new(); /// emit!(errors, "an error message"); /// ``` @@ -305,6 +305,11 @@ mod test { let error = syn2::Error::new(proc_macro2::Span::call_site(), "an error"); emit!(emitter, error); } + #[cfg(feature = "syn3")] + { + let error = syn3::Error::new(proc_macro2::Span::call_site(), "an error"); + emit!(emitter, error); + } } // Only tests that it compiles diff --git a/src/parse_to_tokens.rs b/src/parse_to_tokens.rs index 8c665b3..bca9906 100644 --- a/src/parse_to_tokens.rs +++ b/src/parse_to_tokens.rs @@ -88,7 +88,7 @@ impl ManyhowTry for &WhatType { } } -#[cfg(feature = "syn2")] +#[cfg(all(feature = "syn2", not(doc)))] impl ManyhowParse for &WhatType { fn manyhow_parse(&self, input: impl AnyTokenStream, attr: bool) -> Result { let input = input.into(); @@ -103,14 +103,14 @@ impl ManyhowParse for &WhatType { }) } } -#[cfg(feature = "syn2")] +#[cfg(all(feature = "syn2", not(doc)))] impl ManyhowToTokens for &WhatType { fn manyhow_to_tokens(&self, input: T, tokens: &mut TokenStream) { input.to_tokens(tokens); } } -#[cfg(feature = "syn2")] +#[cfg(all(feature = "syn2", not(doc)))] #[test] #[allow(unused)] fn test_inference() { @@ -137,6 +137,55 @@ fn test_inference() { } } +#[cfg(feature = "syn3")] +impl ManyhowParse for &WhatType { + fn manyhow_parse(&self, input: impl AnyTokenStream, attr: bool) -> Result { + let input = input.into(); + let empty = input.is_empty(); + syn3::parse2(input).map_err(|e| { + let mut e = e.into_compile_error(); + if attr && empty { + error_message!("while parsing attribute argument (`#[... (...)]`)") + .to_tokens(&mut e) + } + e + }) + } +} +#[cfg(feature = "syn3")] +impl ManyhowToTokens for &WhatType { + fn manyhow_to_tokens(&self, input: T, tokens: &mut TokenStream) { + input.to_tokens(tokens); + } +} + +#[cfg(feature = "syn3")] +#[test] +#[allow(unused)] +fn test_inference() { + use syn3::parse::Parse; + + if false { + let wt = &WhatType::new(); + let ts: proc_macro::TokenStream = wt.manyhow_parse(quote::quote!(test), false).unwrap(); + let wt = &WhatType::new(); + if false { + let wt: Result = wt.identify(); + } + let ts: syn3::Ident = wt.manyhow_parse(quote::quote!(test), false).unwrap(); + + struct Parsable; + impl Parse for Parsable { + fn parse(input: syn3::parse::ParseStream) -> syn3::Result { + todo!() + } + } + let wt = &WhatType::new(); + let _: Result = wt.identify(); + let ts = wt.manyhow_parse(quote::quote!(test), false).unwrap(); + } +} + macro_rules! transparent_handlers { ($name:ident; $MacroInput:ident; $($input:ident: $Input:ident $($context:expr)?),*; $($dummy:ident)?) => { /// Internal implementation for macro. diff --git a/src/span_ranged.rs b/src/span_ranged.rs index ede7044..1e6f014 100644 --- a/src/span_ranged.rs +++ b/src/span_ranged.rs @@ -153,6 +153,25 @@ const _: () = { } }; +#[cfg(feature = "syn3")] +const _: () = { + impl SpanRanged for syn3::token::Brace { + fn span_range(&self) -> Range { + self.span.span_range() + } + } + impl SpanRanged for syn3::token::Bracket { + fn span_range(&self) -> Range { + self.span.span_range() + } + } + impl SpanRanged for syn3::token::Paren { + fn span_range(&self) -> Range { + self.span.span_range() + } + } +}; + /// Implementation of [`SpanRanged`](SpanRanged)` for T: `[`ToTokens`] /// /// This is necessary to put in a standalone function due to compiler