ballerina-platform / ballerina-lang

The Ballerina Programming Language
https://ballerina.io/
Apache License 2.0
3.66k stars 750 forks source link

[Task]: Port the nBallerina closure implementation to jBallerina #41753

Open heshanpadmasiri opened 11 months ago

heshanpadmasiri commented 11 months ago

Description

Main purposed changes are to introduce nested functions to jBallerina BIR and avoid lifting nested functions to the module scope as part of desugaring process.

Describe your task(s)

No response

Related area

-> Compilation

Related issue(s) (optional)

Relevant issues in nBallerina

Suggested label(s) (optional)

No response

Suggested assignee(s) (optional)

No response

heshanpadmasiri commented 10 months ago

I am planning to this in fallowing stages

  1. Introduce nested functions to the BIRFunction and make user defined closures use the nested functions.
  2. Make closures created as a part of desugaring phase uses nested functions in the BIR. At this stage we can enforce fallowing invariants
    1. Closures can only capture values that are in it's ancestors or in the global scope
    2. Functions can only directly call non-lambda functions visible in its scope. Lambda must be called via a function pointer and that pointer must be in scope. (This prevents possibility of accidently calling a lambda defined in inside another functions)
  3. Make closure map specific to each closure. At this point we can enforce the invariant each closure can only capture values that are either in scope or captured by it's parent. This would mean in deeply nested functions we need to "bubble up" the captures.
heshanpadmasiri commented 10 months ago

Given current jBallerina implementation don't have a correctness problem, these changes are purely a potential performance improvement (mainly in the domain of garbage collection). Since closures are not prevalent in typical ballerina programs we have decided to temporarily pause work on this. #41769 implements 1 and 2. For 3 we need to move basic type values in to heap and make each closure map pointers to those values. One way to do that would be to introduce wrapper classes for basic types similar to Ref in Kotlin