@@ -2,7 +2,7 @@ use crate::syntax::{ast::App, Context};
22use crate :: { analyze:: Analysis , codegen:: bindings:: interrupt_mod, codegen:: util} ;
33
44use proc_macro2:: TokenStream as TokenStream2 ;
5- use quote:: quote;
5+ use quote:: { format_ident , quote} ;
66
77#[ allow( clippy:: too_many_lines) ]
88pub fn codegen ( ctxt : Context , app : & App , analysis : & Analysis ) -> TokenStream2 {
@@ -129,26 +129,31 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
129129 } ;
130130
131131 let internal_spawn_ident = util:: internal_task_ident ( name, "spawn" ) ;
132+ let internal_spawn_helper_ident = util:: internal_task_ident ( name, "spawn_helper" ) ;
132133 let internal_waker_ident = util:: internal_task_ident ( name, "waker" ) ;
133134 let from_ptr_n_args = util:: from_ptr_n_args_ident ( spawnee. inputs . len ( ) ) ;
134135 let ( input_args, input_tupled, input_untupled, input_ty) =
135136 util:: regroup_inputs ( & spawnee. inputs ) ;
136137
137- let local_task = app. software_tasks [ t] . args . local_task ;
138- let unsafety = if local_task {
139- // local tasks are only safe to call from the same executor
140- quote ! { unsafe }
141- } else {
142- quote ! { }
143- } ;
138+ let generics: Vec < _ > = spawnee. inputs . iter ( ) . enumerate ( ) . map ( |( i, _) | format_ident ! ( "T{i}" ) ) . collect ( ) ;
139+ let generic_input_args = generics. iter ( ) . enumerate ( ) . map ( |( i, generic) | {
140+ let ident = format_ident ! ( "_{i}" ) ;
141+ quote ! { #ident: #generic }
142+ } ) ;
143+ let constraints = generics. iter ( ) . zip ( & spawnee. inputs ) . map ( |( generic, input) | {
144+ let ty = & input. ty ;
145+ quote ! { #generic: rtic:: export:: dummy:: Dummy <T =#ty> + Send + Sync }
146+ } ) ;
144147
145148 // Spawn caller
146149 items. push ( quote ! (
147150 #( #cfgs) *
148- /// Spawns the task directly
151+ /// Spawns the task without checking if the spawner and spawnee are the same priority
152+ ///
153+ /// SAFETY: The caller needs to check that the spawner and spawnee are the same priority
149154 #[ allow( non_snake_case) ]
150155 #[ doc( hidden) ]
151- pub #unsafety fn #internal_spawn_ident ( #( #input_args, ) * ) -> :: core:: result:: Result <( ) , #input_ty> {
156+ pub unsafe fn #internal_spawn_helper_ident ( #( #input_args, ) * ) -> :: core:: result:: Result <( ) , #input_ty> {
152157 // SAFETY: If `try_allocate` succeeds one must call `spawn`, which we do.
153158 unsafe {
154159 let exec = rtic:: export:: executor:: AsyncTaskExecutor :: #from_ptr_n_args( #name, & #exec_name) ;
@@ -162,6 +167,15 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
162167 }
163168 }
164169 }
170+
171+ /// Spawns the task directly
172+ #[ allow( non_snake_case) ]
173+ #[ doc( hidden) ]
174+ pub fn #internal_spawn_ident<#( #generics) , * >( #( #generic_input_args, ) * ) -> :: core:: result:: Result <( ) , #input_ty>
175+ where #( #constraints) , *
176+ {
177+ unsafe { #internal_spawn_helper_ident( #( #input_untupled. to( ) ) , * ) }
178+ }
165179 ) ) ;
166180
167181 // Waker
@@ -183,37 +197,31 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
183197 }
184198 ) ) ;
185199
186- if !local_task {
187- module_items. push ( quote ! (
188- #( #cfgs) *
189- #[ doc( inline) ]
190- pub use super :: #internal_spawn_ident as spawn;
191- ) ) ;
192- }
200+ module_items. push ( quote ! {
201+ #( #cfgs) *
202+ #[ doc( inline) ]
203+ pub use super :: #internal_spawn_ident as spawn;
204+ } ) ;
193205
194- let local_tasks_on_same_executor : Vec < _ > = app
206+ let tasks_on_same_executor : Vec < _ > = app
195207 . software_tasks
196208 . iter ( )
197- . filter ( |( _, t) | t. args . local_task && t . args . priority == priority)
209+ . filter ( |( _, t) | t. args . priority == priority)
198210 . collect ( ) ;
199211
200- if !local_tasks_on_same_executor . is_empty ( ) {
212+ if !tasks_on_same_executor . is_empty ( ) {
201213 let local_spawner = util:: internal_task_ident ( t, "LocalSpawner" ) ;
202214 fields. push ( quote ! {
203215 /// Used to spawn tasks on the same executor
204216 ///
205217 /// This is useful for tasks that take args which are !Send/!Sync.
206- ///
207- /// NOTE: This only works with tasks marked `local_task = true`
208- /// and which have the same priority and thus will run on the
209- /// same executor.
210218 pub local_spawner: #local_spawner
211219 } ) ;
212- let tasks = local_tasks_on_same_executor
220+ let tasks = tasks_on_same_executor
213221 . iter ( )
214222 . map ( |( ident, task) | {
215223 // Copied mostly from software_tasks.rs
216- let internal_spawn_ident = util:: internal_task_ident ( ident, "spawn " ) ;
224+ let internal_spawn_ident = util:: internal_task_ident ( ident, "spawn_helper " ) ;
217225 let attrs = & task. attrs ;
218226 let cfgs = & task. cfgs ;
219227 let inputs = & task. inputs ;
0 commit comments