Repository: dtolnay/async-trait (rust)

Issue:
cannot implement async trait that returning "impl Trait"
Since rust 1.75, we are able to write functions that return `impl Trait` in trait.

I'd like to use it with async_trait, like below:
```rust
#[async_trait::async_trait]
pub trait X {
    type Error;
    async fn x(&self) -> Result<impl AsRef<str> + Send + Sync, Self::Error>;
}
```
The code upon can pass the compilation, but implementing `X` cannot.

```rust
struct T;
#[async_trait::async_trait]
impl X for T {
   type Error = ();
   async fn x(&self) -> Result<impl AsRef<str> + Send + Sync, Self::Error> {
      Ok("Hello World")
   }
}
```

Complation error:
```
error[E0562]: `impl Trait` is not allowed in paths
  --> scratch/src/main.rs:11:33
   |
11 |     async fn x(&self) -> Result<impl AsRef<str> + Send + Sync, Self::Error> {
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods

error[E0562]: `impl Trait` is not allowed in the type of variable bindings
  --> scratch/src/main.rs:11:33
   |
11 |     async fn x(&self) -> Result<impl AsRef<str> + Send + Sync, Self::Error> {
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
```

After inspecting code generated by `async_trait` macro:
```rust
impl X for T {
    type Error = ();
    #[allow(
        elided_named_lifetimes,
        clippy::async_yields_async,
        clippy::diverging_sub_expression,
        clippy::let_unit_value,
        clippy::needless_arbitrary_self_type,
        clippy::no_effect_underscore_binding,
        clippy::shadow_same,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds,
        clippy::used_underscore_binding
    )]
    fn x<'life0, 'async_trait>(
        &'life0 self,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<
                Output = Result<impl AsRef<str>, Self::Error>,
            > + ::core::marker::Send + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        Box::pin(async move {
            if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<
                Result<impl AsRef<str> + Send + Sync, Self::Error>,
            > {
                #[allow(unreachable_code)] return __ret;
            }
            let __self = self;
            let __ret: Result<impl AsRef<str> + Send + Sync, Self::Error> = { Ok("Hello World") };
            #[allow(unreachable_code)] __ret
        })
    }
}
```
Upon inspecting the generated code by the async_trait macro, the `impl Trait` appears in type annotations, causing the issue. Replacing these occurrences of `impl Trait` with `_` resolves the compilation errors.

Can the macro automatically replace all instances of `impl Trait` with `_` to bypass this issue?



Pull request:
Support impl Trait in return type
Closes #281.

Patch:
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<WhereClause>) -> &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);
+}


Test patch:
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<impl AsRef<str> + Send + Sync, Self::Error>;
+    }
+
+    pub struct T;
+
+    #[async_trait]
+    impl Trait for T {
+        type Error = ();
+        async fn method(&self) -> Result<impl AsRef<str> + Send + Sync, Self::Error> {
+            Ok("Hello World")
+        }
+    }
+}