diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d477a8..befd90f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [nightly, beta, stable, 1.70.0, 1.56.0] + rust: [nightly, beta, stable, 1.75.0, 1.70.0, 1.56.0] timeout-minutes: 45 steps: - uses: actions/checkout@v4 diff --git a/Cargo.toml b/Cargo.toml index 3590089..050b10a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.74" quote = "1.0.35" -syn = { version = "2.0.46", default-features = false, features = ["full", "parsing", "printing", "proc-macro", "visit-mut"] } +syn = { version = "2.0.46", default-features = false, features = ["clone-impls", "full", "parsing", "printing", "proc-macro", "visit-mut"] } [dev-dependencies] futures = "0.3.30" diff --git a/src/expand.rs b/src/expand.rs index 5adba58..df02106 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -12,7 +12,7 @@ use syn::visit_mut::{self, VisitMut}; use syn::{ parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericArgument, GenericParam, Generics, Ident, ImplItem, Lifetime, LifetimeParam, Pat, PatIdent, PathArguments, Receiver, - ReturnType, Signature, Token, TraitItem, Type, TypePath, WhereClause, + ReturnType, Signature, Token, TraitItem, Type, TypeInfer, TypePath, WhereClause, }; impl ToTokens for Item { @@ -410,6 +410,8 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) { quote!(#(#decls)* { #(#stmts)* }) } } else { + let mut ret = ret.clone(); + replace_impl_trait_with_infer(&mut ret); quote! { if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> { #[allow(unreachable_code)] @@ -475,3 +477,20 @@ fn where_clause_or_default(clause: &mut Option) -> &mut WhereClause predicates: Punctuated::new(), }) } + +fn replace_impl_trait_with_infer(ty: &mut Type) { + struct ReplaceImplTraitWithInfer; + + impl VisitMut for ReplaceImplTraitWithInfer { + fn visit_type_mut(&mut self, ty: &mut Type) { + if let Type::ImplTrait(impl_trait) = ty { + *ty = Type::Infer(TypeInfer { + underscore_token: Token![_](impl_trait.impl_token.span), + }); + } + visit_mut::visit_type_mut(self, ty); + } + } + + ReplaceImplTraitWithInfer.visit_type_mut(ty); +} diff --git a/tests/test.rs b/tests/test.rs index 7fd5e83..5d1c549 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1661,3 +1661,25 @@ pub mod issue277 { fn g(_: &mut &()) {} } + +// https://github.com/dtolnay/async-trait/issues/281 +#[rustversion::since(1.75)] +pub mod issue281 { + use async_trait::async_trait; + + #[async_trait] + pub trait Trait { + type Error; + async fn method(&self) -> Result + Send + Sync, Self::Error>; + } + + pub struct T; + + #[async_trait] + impl Trait for T { + type Error = (); + async fn method(&self) -> Result + Send + Sync, Self::Error> { + Ok("Hello World") + } + } +}