package runtime_test import "testing" func TestTailCall(t *testing.T) { expect(t, ` fac := func(n, a) { if n == 1 { return a } return fac(n-1, n*a) } out = fac(5, 1)`, nil, 120) expect(t, ` fac := func(n, a) { if n == 1 { return a } x := {foo: fac} // indirection for test return x.foo(n-1, n*a) } out = fac(5, 1)`, nil, 120) expect(t, ` fib := func(x, s) { if x == 0 { return 0 + s } else if x == 1 { return 1 + s } return fib(x-1, fib(x-2, s)) } out = fib(15, 0)`, nil, 610) expect(t, ` fib := func(n, a, b) { if n == 0 { return a } else if n == 1 { return b } return fib(n-1, b, a + b) } out = fib(15, 0, 1)`, nil, 610) // global variable and no return value expect(t, ` out = 0 foo := func(a) { if a == 0 { return } out += a foo(a-1) } foo(10)`, nil, 55) expect(t, ` f1 := func() { f2 := 0 // TODO: this might be fixed in the future f2 = func(n, s) { if n == 0 { return s } return f2(n-1, n + s) } return f2(5, 0) } out = f1()`, nil, 15) // tail-call replacing loop // without tail-call optimization, this code will cause stack overflow expect(t, ` iter := func(n, max) { if n == max { return n } return iter(n+1, max) } out = iter(0, 9999) `, nil, 9999) expect(t, ` c := 0 iter := func(n, max) { if n == max { return } c++ iter(n+1, max) } iter(0, 9999) out = c `, nil, 9999) } // tail call with free vars func TestTailCallFreeVars(t *testing.T) { expect(t, ` func() { a := 10 f2 := 0 f2 = func(n, s) { if n == 0 { return s + a } return f2(n-1, n+s) } out = f2(5, 0) }()`, nil, 25) }