Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ jobs:
- run: cargo install cargo-expand
- run: cargo test --verbose

msrv:
name: MSRV
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@1.71.0
# Only the library is covered by rust-version; dev-dependencies need a newer toolchain.
- run: cargo check --lib

fmt:
name: Fmt
runs-on: ubuntu-latest
Expand All @@ -43,7 +52,7 @@ jobs:
- uses: dtolnay/rust-toolchain@nightly
with:
components: clippy
- run: cargo clippy -- -Dwarnings
- run: cargo clippy --all-targets -- -Dwarnings

outdated:
name: Outdated
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name = "async-recursion"
version = "1.1.1"
authors = ["Robert Usher <266585+dcchut@users.noreply.github.com>"]
edition = "2018"
rust-version = "1.71"
license = "MIT OR Apache-2.0"
description = "Recursion for async functions"
repository = "https://github.com/dcchut/async-recursion"
Expand All @@ -15,7 +16,7 @@ proc-macro = true
[dependencies]
proc-macro2 = { version = "1.0", default-features = false }
quote = { version = "1.0", default-features = false }
syn = { version = "2.0", features = ["full", "visit-mut", "parsing", "printing", "proc-macro", "clone-impls"], default-features = false }
syn = { version = "3.0", features = ["full", "visit-mut", "parsing", "printing", "proc-macro", "clone-impls"], default-features = false }

[dev-dependencies]
futures-executor = "0.3"
Expand Down
32 changes: 16 additions & 16 deletions src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{
parse_quote, punctuated::Punctuated, visit_mut::VisitMut, Block, Lifetime, Receiver,
ReturnType, Signature, TypeReference, WhereClause,
ReceiverKind, ReturnType, Signature, TypeReference, WhereClause,
};

use crate::parse::{AsyncItem, RecursionArgs};
Expand Down Expand Up @@ -50,22 +50,21 @@ struct ReferenceVisitor {

impl VisitMut for ReferenceVisitor {
fn visit_receiver_mut(&mut self, receiver: &mut Receiver) {
self.self_lifetime = Some(if let Some((_, lt)) = &mut receiver.reference {
self.self_receiver = true;

if let Some(lt) = lt {
lt.clone()
} else {
// Use 'life_self to avoid collisions with 'life<count> lifetimes.
let new_lifetime: Lifetime = parse_quote!('life_self);
lt.replace(new_lifetime.clone());

self.self_receiver_new_lifetime = true;
// TODO: Support ReceiverKind::Typed as well
let ReceiverKind::Reference(_, lt, _) = &mut receiver.kind else {
return;
};

new_lifetime
}
self.self_receiver = true;
self.self_lifetime = Some(if let Some(lt) = lt {
lt.clone()
} else {
return;
// Use 'life_self to avoid collisions with 'life<count> lifetimes.
let new_lifetime: Lifetime = parse_quote!('life_self);
lt.replace(new_lifetime.clone());

self.self_receiver_new_lifetime = true;
new_lifetime
});
}

Expand Down Expand Up @@ -127,7 +126,8 @@ fn transform_sig(sig: &mut Signature, args: &RecursionArgs) {

// Add an S : 'async_recursion bound to any generic parameter
for param in sig.generics.type_params() {
let ident = param.ident.clone();
let mut ident = param.ident.clone();
ident.set_span(Span::call_site());
where_clause_generics.push(ident);
requires_lifetime = true;
}
Expand Down
2 changes: 2 additions & 0 deletions tests/generic_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub async fn generic_parameter<S: ThirtySeven + Send>(mut x: S) -> u64 {
}
}

// x is only used in the recursive call, but we need it to test a non-Send T under ?Send
#[allow(clippy::only_used_in_recursion)]
#[async_recursion(?Send)]
pub async fn generic_parameter_no_send<T>(x: T, y: u64) -> u64 {
if y > 0 {
Expand Down
26 changes: 13 additions & 13 deletions tests/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ async fn contains_value_2<'a, 'b, T: PartialEq>(value: &'b T, node: &'b Node<'a,
contains_value(value, node).await
}

// The reference inside foo needs a `async_recursion bound
// The reference inside name needs a `async_recursion bound
#[async_recursion]
async fn count_down(foo: Option<&str>) -> i32 {
let _ = foo;
async fn count_down(name: Option<&str>) -> i32 {
let _ = name;
0
}

Expand All @@ -63,17 +63,17 @@ fn lifetime_expansion_works() {
node.left = Some(&left);
node.right = Some(&right);

assert_eq!(contains_value(&3, &node).await, true);
assert_eq!(contains_value(&4, &node).await, false);
assert_eq!(contains_value(&17, &node).await, true);
assert_eq!(contains_value(&13, &node).await, true);
assert_eq!(contains_value(&12, &node).await, false);
assert!(contains_value(&3, &node).await);
assert!(!contains_value(&4, &node).await);
assert!(contains_value(&17, &node).await);
assert!(contains_value(&13, &node).await);
assert!(!contains_value(&12, &node).await);

assert_eq!(contains_value_2(&3, &node).await, true);
assert_eq!(contains_value_2(&4, &node).await, false);
assert_eq!(contains_value_2(&17, &node).await, true);
assert_eq!(contains_value_2(&13, &node).await, true);
assert_eq!(contains_value_2(&12, &node).await, false);
assert!(contains_value_2(&3, &node).await);
assert!(!contains_value_2(&4, &node).await);
assert!(contains_value_2(&17, &node).await);
assert!(contains_value_2(&13, &node).await);
assert!(!contains_value_2(&12, &node).await);

count_down(None).await;
explicit_async_recursion_bound(None).await;
Expand Down
3 changes: 2 additions & 1 deletion tests/struct_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ fn struct_method_with_generic_parameter_works() {
block_on(async move {
let e = Empty {};
assert_eq!(
e.generic_parameter::<*const u64>(&(0 as *const u64)).await,
e.generic_parameter::<*const u64>(&std::ptr::null::<u64>())
.await,
0
);
})
Expand Down
Loading