winglang / wing

A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡
https://winglang.io
Other
5.01k stars 196 forks source link

Recursion support - cannot write `cloud.Function` that calls itself #4696

Open Chriscbr opened 11 months ago

Chriscbr commented 11 months ago

I tried this:

bring cloud;
let fib = new cloud.Function(inflight (payload: str): str => {
  let n = num.fromStr(payload);
  if n < 3 {
    return "1";
  } else {
    let f1 = num.fromStr(fib("${n - 1}"));
    let f2 = num.fromStr(fib("${n - 2}"));
    return "${f1 + f2}";
  }
});

This happened:

When I compile it to the simulator:

ERROR: Cannot access 'fib' before initialization

examples/tests/valid/target/test/load_test.test.wsim.905075.tmp/.wing/preflight.js:39
         _registerOnLift(host, ops) {
           if (ops.includes("handle")) {
>>           $Closure1._registerOnLiftObject(fib, host, ["invoke"]);
           }
           super._registerOnLift(host, ops);

I expected this:

I expected the error to be caught during type checking (or miraculously for the example to compile)

Is there a workaround?

No response

Component

Compiler

Wing Version

0.41.22

Node.js Version

18.14.1

Platform(s)

MacOS

Anything else?

No response

Community Notes

Chriscbr commented 11 months ago

If I try without wrapping the inflight closure inside cloud.Function, I get a different error:

let fib = inflight (payload: str): str => {
  let n = num.fromStr(payload);
  if n < 3 {
    return "1";
  } else {
    let f1 = num.fromStr(fib("${n - 1}"));
    let f2 = num.fromStr(fib("${n - 2}"));
    return "${f1 + f2}";
  }
};

test "fib" {
  assert(fib("10") == "55");
}
ERROR: Maximum call stack size exceeded

examples/tests/valid/target/test/load_test.test.wsim.114055.tmp/.wing/preflight.js:18
           return `
             require("./inflight.$Closure1-1.js")({
>>             $fib: ${context._lift(fib)},
               $std_Number: ${context._lift($stdlib.core.toLiftableModuleType(std.Number, "@winglang/sdk/std", "Number"))},
             })
Chriscbr commented 11 months ago

The only cases this works today is if the function is defined in the same phase (i.e. a preflight function defined in preflight, or an inflight function defined in inflight):

let fib = (payload: str): str => {
  let n = num.fromStr(payload);
  if n < 3 {
    return "1";
  } else {
    let f1 = num.fromStr(fib("${n - 1}"));
    let f2 = num.fromStr(fib("${n - 2}"));
    return "${f1 + f2}";
  }
};

assert(fib("10") == "55");
github-actions[bot] commented 9 months ago

Hi,

This issue hasn't seen activity in 60 days. Therefore, we are marking this issue as stale for now. It will be closed after 7 days. Feel free to re-open this issue when there's an update or relevant information to be added. Thanks!