Description
Under Windows lpython
I tried to compile/run following fib.py
file:
def fib(n: i32) -> i32:
return fib(n - 1) + fib(n - 2) if n >= 3 else 1
print(fib(30))
above program silently crashes. In regular CPython code above works well!
While same non-recursive variant
def fib(n: i32) -> i32:
a: i32 = 1
b: i32 = 1
i: i32 = 0
for i in range(n - 2):
a, b = b, a + b
return b
print(fib(30))
runs in LPython without any problem and outputs correct answer 832040
================== UPDATE 1 ==================
It appeared that only LLVM IR assembly is damaged by recursive crash, but C++ code doesn't.
I.e. if you do --show-llvm and compile .ll file manually through CLang then it crashes, but if you do --show-cpp and compile .cpp through CLang then it doesn't crash and produces correct output.
It appeared that most probably Python's default IF-ELSE inline statement is not interpreted correctly. Because following rewrite of code
def fib(n: i32) -> i32:
if n >= 3:
return fib(n - 1) + fib(n - 2)
else:
return 1
print(fib(30))
works correctly and doesn't crash.
It means that A if B else C
is converted to LLVM by LPython incorrectly. As you should know this statement should be lazy, meaning that you can't compute both A and C beforehand and then use one of results.
But if you look into LLVM IR assembly of the very first program of this post then you'll see something like this:
define i32 @__module___main___fib(i32* %n) {
...................................
%1 = icmp sge i32 %0, 3
......... LOTS OF LINES computing both clauses of IF-ELSE beforehand without using %1 ...........
%9 = select i1 %1, i32 %8, i32 1
store i32 %9, i32* %_lpython_return_variable, align 4
br label %return
....................
So you'll see that first it computes condition, then doesn't use this condition but computes both clauses of IF-ELSE without using result of condition, and at the very end it returns one of computed clause.
This is incorrect for Python's IF-ELSE and even for C++'s ternary B ? A : C
, both Python and C++ SHOULD be lazy for this ternary operator.
Without LAZY evaluation of IF-ELSE of course fib() function will go into Infinite recursion and thus crash stack through overflow.