embassy-executor: explicitly return impl Future in task inner task

This commit is contained in:
Brezak 2025-07-23 19:51:31 +02:00
parent 1b42e62424
commit 539ff78ebb
No known key found for this signature in database
GPG Key ID: CB3891E2B1279D7C
4 changed files with 31 additions and 9 deletions

View File

@ -5,7 +5,7 @@ use darling::FromMeta;
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::visit::{self, Visit};
use syn::{Expr, ExprLit, Lit, LitInt, ReturnType, Type};
use syn::{Expr, ExprLit, Lit, LitInt, ReturnType, Type, Visibility};
use crate::util::*;
@ -135,6 +135,13 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
let task_inner_future_output = match &f.sig.output {
ReturnType::Default => quote! {-> impl ::core::future::Future<Output = ()>},
// Special case the never type since we can't stuff it into a `impl Future<Output = !>`
ReturnType::Type(arrow, maybe_never)
if f.sig.asyncness.is_some() && matches!(**maybe_never, Type::Never(_)) =>
{
quote! {
#arrow impl ::core::future::Future<Output=#embassy_executor::_export::Never>
}
}
ReturnType::Type(arrow, maybe_never) if matches!(**maybe_never, Type::Never(_)) => quote! {
#arrow #maybe_never
},
@ -149,14 +156,20 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
},
};
// We have to rename the function since it might be recursive;
let mut task_inner_function = f.clone();
let task_inner_function_ident = format_ident!("__{}_task_inner_function", task_ident);
task_inner_function.sig.ident = task_inner_function_ident.clone();
task_inner_function.vis = Visibility::Inherited;
let task_inner_body = if errors.is_empty() {
quote! {
#f
#task_inner_function
// SAFETY: All the preconditions to `#task_ident` apply to
// all contexts `#task_inner_ident` is called in
#unsafety {
#task_ident(#(#full_args,)*)
#task_inner_function_ident(#(#full_args,)*)
}
}
} else {

View File

@ -216,7 +216,7 @@ pub mod _export {
);
#[allow(dead_code)]
trait HasOutput {
pub trait HasOutput {
type Output;
}
@ -225,7 +225,7 @@ pub mod _export {
}
#[allow(dead_code)]
type Never = <fn() -> ! as HasOutput>::Output;
pub type Never = <fn() -> ! as HasOutput>::Output;
}
/// Implementation details for embassy macros.
@ -242,7 +242,7 @@ pub mod _export {
impl TaskReturnValue for Never {}
#[allow(dead_code)]
trait HasOutput {
pub trait HasOutput {
type Output;
}
@ -251,5 +251,5 @@ pub mod _export {
}
#[allow(dead_code)]
type Never = <fn() -> ! as HasOutput>::Output;
pub type Never = <fn() -> ! as HasOutput>::Output;
}

View File

@ -7,7 +7,7 @@ use std::sync::{Arc, Mutex};
use std::task::Poll;
use embassy_executor::raw::Executor;
use embassy_executor::task;
use embassy_executor::{task, Spawner};
#[export_name = "__pender"]
fn __pender(context: *mut ()) {
@ -317,3 +317,12 @@ fn executor_task_cfg_args() {
let (_, _, _) = (a, b, c);
}
}
#[test]
fn recursive_task() {
#[embassy_executor::task(pool_size = 2)]
async fn task1() {
let spawner = unsafe { Spawner::for_current_executor().await };
spawner.spawn(task1());
}
}

View File

@ -7,4 +7,4 @@ error[E0277]: task futures must resolve to `()` or `!`
= note: use `async fn` or change the return type to `impl Future<Output = ()>`
= help: the following other types implement trait `TaskReturnValue`:
()
<fn() -> ! as _export::HasOutput>::Output
<fn() -> ! as HasOutput>::Output