@@ -589,36 +589,39 @@ macro_rules! impl_script_function {
589589
590590 $( let $context = caller_context; ) ?
591591 let world = caller_context. world( ) ?;
592- world. begin_access_scope( ) ?;
593- let mut current_arg = 0 ;
594-
595- $(
596- current_arg += 1 ;
597- let $param = args. pop_front( ) ;
598- let $param = match $param {
599- Some ( $param) => $param,
600- None => {
601- if let Some ( default ) = <$param>:: default_value( ) {
602- default
603- } else {
604- return Err ( InteropError :: argument_count_mismatch( expected_arg_count, received_args_len) ) ;
605- }
606- }
607- } ;
608- let $param = <$param>:: from_script( $param, world. clone( ) )
609- . map_err( |e| InteropError :: function_arg_conversion_error( current_arg. to_string( ) , e) ) ?;
610- ) *
611-
612- let ret = {
613- let out = self ( $( $context, ) ? $( $param. into( ) , ) * ) ;
614- $(
615- let $out = out?;
616- let out = $out;
617- ) ?
618- out. into_script( world. clone( ) ) . map_err( |e| InteropError :: function_arg_conversion_error( "return value" . to_owned( ) , e) )
592+ // Safety: we're not holding any references to the world, the arguments which might have aliased will always be dropped
593+ let ret: Result <ScriptValue , InteropError > = unsafe {
594+ world. with_access_scope( ||{
595+ let mut current_arg = 0 ;
596+
597+ $(
598+ current_arg += 1 ;
599+ let $param = args. pop_front( ) ;
600+ let $param = match $param {
601+ Some ( $param) => $param,
602+ None => {
603+ if let Some ( default ) = <$param>:: default_value( ) {
604+ default
605+ } else {
606+ return Err ( InteropError :: argument_count_mismatch( expected_arg_count, received_args_len) ) ;
607+ }
608+ }
609+ } ;
610+ let $param = <$param>:: from_script( $param, world. clone( ) )
611+ . map_err( |e| InteropError :: function_arg_conversion_error( current_arg. to_string( ) , e) ) ?;
612+ ) *
613+
614+ let ret = {
615+ let out = self ( $( $context, ) ? $( $param. into( ) , ) * ) ;
616+ $(
617+ let $out = out?;
618+ let out = $out;
619+ ) ?
620+ out. into_script( world. clone( ) ) . map_err( |e| InteropError :: function_arg_conversion_error( "return value" . to_owned( ) , e) )
621+ } ;
622+ ret
623+ } ) ?
619624 } ;
620- // Safety: we're not holding any references to the world, the arguments which might have aliased have been dropped
621- unsafe { world. end_access_scope( ) ? } ;
622625 ret
623626 } ) ( ) ;
624627 let script_value: ScriptValue = res. into( ) ;
@@ -695,6 +698,25 @@ mod test {
695698 } ) ;
696699 }
697700
701+ #[ test]
702+ fn test_interrupted_call_releases_access_scope ( ) {
703+ #[ derive( bevy:: prelude:: Component , Reflect ) ]
704+ struct Comp ;
705+
706+ let fn_ = |_a : crate :: bindings:: function:: from:: Mut < Comp > | 0usize ;
707+ let script_function = fn_. into_dynamic_script_function ( ) . with_name ( "my_fn" ) ;
708+
709+ with_local_world ( || {
710+ let out =
711+ script_function. call ( vec ! [ ScriptValue :: from( 1 ) ] , FunctionCallContext :: default ( ) ) ;
712+
713+ assert ! ( out. is_err( ) ) ;
714+ let world = FunctionCallContext :: default ( ) . world ( ) . unwrap ( ) ;
715+ // assert no access is held
716+ assert ! ( world. list_accesses( ) . is_empty( ) ) ;
717+ } ) ;
718+ }
719+
698720 #[ test]
699721 fn test_overloaded_script_function ( ) {
700722 let mut registry = ScriptFunctionRegistry :: default ( ) ;
0 commit comments