1- use std:: { collections:: { BTreeMap , VecDeque } , rc:: Rc } ;
2-
3- use crate :: { cache:: DefinitionInfoId , hir:: { self , Type } , parser:: ast, types:: { self , effects:: Effect , typed:: Typed } , util:: fmap} ;
1+ use std:: {
2+ collections:: { BTreeMap , VecDeque } ,
3+ rc:: Rc ,
4+ } ;
5+
6+ use crate :: {
7+ cache:: DefinitionInfoId ,
8+ hir:: { self , Type } ,
9+ parser:: ast,
10+ types:: { self , effects:: Effect , typed:: Typed } ,
11+ util:: fmap,
12+ } ;
413
514use super :: { tuple, unwrap_variable, Context , Definition } ;
615
@@ -103,6 +112,10 @@ impl<'c> Context<'c> {
103112 args. push ( hir:: Ast :: Variable ( variable) ) ;
104113 }
105114
115+ if let Some ( frame) = self . effect_continuations . last ( ) {
116+ args. extend ( frame. iter ( ) . map ( |( _, k) | hir:: Ast :: Variable ( k. clone ( ) ) ) ) ;
117+ }
118+
106119 let ret_type = self . convert_type ( handle. get_type ( ) . unwrap ( ) ) ;
107120 let function = Box :: new ( handler_fn) ;
108121 let function_type = hir:: FunctionType :: new ( vec ! [ Type :: continuation( ) ] , ret_type. clone ( ) ) ;
@@ -177,6 +190,17 @@ impl<'c> Context<'c> {
177190 parameters. push ( self . convert_type ( free_var_type) ) ;
178191 }
179192
193+ // Redefine and push effect handlers since we can't use local variables from another function
194+ if let Some ( frame) = self . effect_continuations . last ( ) . cloned ( ) {
195+ let new_frame = fmap ( frame, |( effect, _old_k) | {
196+ parameters. push ( Type :: continuation ( ) ) ;
197+
198+ let new_k = self . fresh_variable ( Type :: continuation ( ) ) ;
199+ ( effect. clone ( ) , new_k)
200+ } ) ;
201+ self . effect_continuations . push ( new_frame) ;
202+ }
203+
180204 let result_type = self . convert_type ( handle. get_type ( ) . unwrap ( ) ) ;
181205 let return_type = Box :: new ( result_type. clone ( ) ) ;
182206 let function_type = hir:: FunctionType { parameters, return_type, is_varargs : false } ;
@@ -227,6 +251,11 @@ impl<'c> Context<'c> {
227251 args. push ( variable) ;
228252 }
229253
254+ // Push any captured effect continuations too
255+ if let Some ( frame) = self . effect_continuations . last ( ) {
256+ args. extend ( frame. iter ( ) . map ( |( _, k) | k. clone ( ) ) ) ;
257+ }
258+
230259 let lambda = hir:: Ast :: Lambda ( hir:: Lambda { args, body, typ : function_type } ) ;
231260
232261 let definition = hir:: Ast :: Definition ( hir:: Definition {
@@ -237,6 +266,7 @@ impl<'c> Context<'c> {
237266 expr : Box :: new ( lambda) ,
238267 } ) ;
239268
269+ self . pop_continuation_parameters ( ) ;
240270 handle_function_var. definition = Some ( Rc :: new ( definition) ) ;
241271 hir:: Ast :: Variable ( handle_function_var)
242272 }
@@ -350,7 +380,9 @@ impl<'c> Context<'c> {
350380 let typ = self . follow_all_bindings ( & typ) ;
351381 let monomorphized_type = Rc :: new ( self . convert_type ( & typ) ) ;
352382
353- let resume_function = self . make_resume_function ( & monomorphized_type, handler_function, free_vars) ;
383+ let function_effects = self . get_effects ( & typ) ;
384+ let resume_function =
385+ self . make_resume_function ( & monomorphized_type, handler_function, free_vars, function_effects) ;
354386
355387 // `resume`'s closure environment is any free variable used by any of the effect branches
356388 // plus the continuation `k`.
@@ -395,6 +427,7 @@ impl<'c> Context<'c> {
395427 /// ```
396428 fn make_resume_function (
397429 & mut self , typ : & Type , handler_function : & hir:: Variable , free_vars : & BTreeMap < DefinitionInfoId , types:: Type > ,
430+ mut function_effects : Vec < Effect > ,
398431 ) -> hir:: Ast {
399432 use hir:: { Ast :: Builtin , Builtin :: ContinuationArgPush } ;
400433 let mut function_type = match typ {
@@ -411,14 +444,35 @@ impl<'c> Context<'c> {
411444 let environment_size = free_vars. len ( ) + 1 ;
412445 Self :: fix_resume_environment_type ( environment_type, environment_size) ;
413446
414- let lambda_args = fmap ( & function_type. parameters , |param| {
447+ function_effects. reverse ( ) ;
448+ let mut effect_continuations = Vec :: with_capacity ( function_effects. len ( ) ) ;
449+
450+ let lambda_args = fmap ( function_type. parameters . iter ( ) . enumerate ( ) , |( i, param) | {
415451 let definition_id = self . next_unique_id ( ) ;
416- hir:: DefinitionInfo { definition : None , definition_id, typ : Rc :: new ( param. clone ( ) ) , name : None }
452+ let var = hir:: DefinitionInfo { definition : None , definition_id, typ : Rc :: new ( param. clone ( ) ) , name : None } ;
453+
454+ // Check if this parameter is a Continuation that is not this resume's continuation.
455+ // If it is this resume's continuation it'll always be in the captured environment, so
456+ // we skip that last parameter. If it is not this resume's continuation, it should have
457+ // been pushed as a continuation parameter before the environment parameter.
458+ let is_env_param = i == function_type. parameters . len ( ) - 1 ;
459+ if !is_env_param && * param == Type :: continuation ( ) {
460+ let effect = function_effects. pop ( ) . expect ( "Expected effect handler" ) ;
461+ effect_continuations. push ( ( effect, var. clone ( ) ) ) ;
462+ }
463+ var
417464 } ) ;
465+ self . effect_continuations . push ( effect_continuations) ;
418466
419467 let environment = lambda_args. last ( ) . unwrap ( ) . clone ( ) ;
420468
421- let ( k_var, mut statements, call_args) = self . unpack_resume_environment ( free_vars, environment) ;
469+ let ( k_var, mut statements, mut call_args) = self . unpack_resume_environment ( free_vars, environment) ;
470+
471+ // Push any effect continuations that aren't handled by this Handle as well
472+ if let Some ( frame) = self . effect_continuations . last ( ) {
473+ call_args. extend ( frame. iter ( ) . map ( |( _, k) | hir:: Ast :: Variable ( k. clone ( ) ) ) ) ;
474+ }
475+
422476 let k = hir:: Ast :: Variable ( k_var. clone ( ) ) ;
423477
424478 // Push each parameter to the continuation
@@ -438,6 +492,7 @@ impl<'c> Context<'c> {
438492 function_type : hir:: FunctionType :: new ( vec ! [ Type :: continuation( ) ] , result_type) ,
439493 } ) ) ;
440494
495+ self . pop_continuation_parameters ( ) ;
441496 let body = Box :: new ( hir:: Ast :: Sequence ( hir:: Sequence { statements } ) ) ;
442497 hir:: Ast :: Lambda ( hir:: Lambda { args : lambda_args, body, typ : function_type } )
443498 }
0 commit comments