From aff365fb7477e0952d0196ea369ddec9c7ed3c78 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 2 Jan 2025 20:11:27 -0800 Subject: [PATCH 1/3] Add regression test for issue 281 Without #![feature(impl_trait_in_bindings)]: error[E0562]: `impl Trait` is not allowed in paths --> tests/test.rs:1680:42 | 1680 | async fn method(&self) -> Result + 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 --> tests/test.rs:1680:42 | 1680 | async fn method(&self) -> Result + Send + Sync, Self::Error> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `impl Trait` is only allowed in arguments and return types of functions and methods = note: see issue #63065 for more information = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable = note: this compiler was built on 2025-01-02; consider upgrading it if it is out of date With #![feature(impl_trait_in_bindings)]: error[E0562]: `impl Trait` is not allowed in paths --> tests/test.rs:1680:42 | 1680 | async fn method(&self) -> Result + Send + Sync, Self::Error> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `impl Trait` is only allowed in arguments and return types of functions and methods --- tests/test.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test.rs b/tests/test.rs index 7fd5e83..1ff58c6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1661,3 +1661,24 @@ pub mod issue277 { fn g(_: &mut &()) {} } + +// https://github.com/dtolnay/async-trait/issues/281 +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") + } + } +} From 85b572c44236deab9550572183953b9df743939d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 2 Jan 2025 20:19:08 -0800 Subject: [PATCH 2/3] Support impl Trait in return type --- Cargo.toml | 2 +- src/expand.rs | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) 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); +} From 3af8236a3d7cdee1d89435b27375c219cf265cbe Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 2 Jan 2025 20:21:43 -0800 Subject: [PATCH 3/3] Require Rust 1.75+ for RPITIT (return position impl trait in trait) --- .github/workflows/ci.yml | 2 +- tests/test.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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/tests/test.rs b/tests/test.rs index 1ff58c6..5d1c549 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1663,6 +1663,7 @@ pub mod issue277 { } // https://github.com/dtolnay/async-trait/issues/281 +#[rustversion::since(1.75)] pub mod issue281 { use async_trait::async_trait;