lcompilers / lpython

Python compiler
https://lpython.org/
Other
1.5k stars 157 forks source link

Unhandled exception returning array from function #2494

Open rebcabin opened 7 months ago

rebcabin commented 7 months ago

All these work in CPython. LPython produces an unhandled exception:

from numpy import empty, int16
from numpy import empty, int16

from lpython import (i16, i32, Allocatable)

# doesn't work:
# def to_lpython_array(n: i32, m: i32) -> Array[i16, n, m]: #ndarray(Any, dtype=int16):
# works:
# def to_lpython_array(n: i32, m: i32) -> Array[i16, 15, 3]: #ndarray(Any, dtype=int16):
# doesn't work:
def to_lpython_array(n: i32, m: i32) -> Allocatable[i16[:]]:
    A_nm: i16[n, m] = empty((n, m), dtype=int16)
    return A_nm
(lp) ┌─(~/Documents/GitHub/lpython/integration_tests)────────────────────────────────────────────────────────────────────────────────(brian@MacBook-Pro:s001)─┐
└─(12:57:01 on vector-backend ✹ ✭)──> lpython ../ISSUES/UNHANDLED-EXCEPTIONS/Issue2494.py                                              1 ↵ ──(Tue,Feb06)─┘
Internal Compiler Error: Unhandled exception
Traceback (most recent call last):
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/bin/lpython.cpp", line 1872
    err = compile_python_to_object_file(arg_file, tmp_o, runtime_library_dir,
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/bin/lpython.cpp", line 824
    res = fe.get_llvm3(*asr, pass_manager, diagnostics, infile);
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/lpython/python_evaluator.cpp", line 71
    run_fn, infile);
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/codegen/asr_to_llvm.cpp", line 9276
    pass_manager.apply_passes(al, &asr, co.po, diagnostics);
  File "/Users/brian/Documents/GitHub/lpython/src/libasr/pass/pass_manager.h", line 299
    apply_passes(al, asr, _passes, pass_options, diagnostics);
  File "/Users/brian/Documents/GitHub/lpython/src/libasr/pass/pass_manager.h", line 160
    _passes_db[passes[i]](al, *asr, pass_options);
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 1908
    v.visit_TranslationUnit(unit);
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 1550
    ASR::symbol_t *mod = x.m_symtab->get_symbol(item);
  File "../libasr/asr.h", line 5060
  File "../libasr/asr.h", line 4774
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 1570
    for (auto &item : x.m_symtab->get_scope()) {
  File "../libasr/asr.h", line 5060
  File "../libasr/asr.h", line 4775
  File "../libasr/asr.h", line 45906
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 1521
    visit_stmt(*m_body[i]);
  File "../libasr/asr.h", line 5077
  File "../libasr/asr.h", line 4799
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 1725
    visit_AssignmentUtil(x);
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 1607
    current_expr = const_cast<ASR::expr_t**>(&(x.m_value));
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 1501
    replacer.replace_expr(*current_expr);
  File "../libasr/asr.h", line 45074
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 391
    replace_vars_helper(x);
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 280
    *current_expr = nullptr;
  File "/Users/brian/Dropbox/Mac/Documents/GitHub/lpython/src/libasr/pass/array_op.cpp", line 120
    LCOMPILERS_ASSERT(result_rank >= var_rank);
AssertFailed: result_rank >= var_rank
rebcabin commented 7 months ago

The following is a workaround. Leaving this open as a Design Change Request because I would like to see either documentation or a more discoverable / intuitive design for returning arrays from functions:

rows = TypeVar("rows")
cols = TypeVar("cols")

def load_lpython_array_from_c_fortran_array(b: CPtr, rows: i32, cols: i32) -> i16[rows, cols]:
    """Load an LPython array from a C / Fortran array."""
    B: Pointer[i16[:]] = c_p_pointer(b, i16[:], array([rows * cols]))
    D: i16[rows, cols] = empty((rows, cols), dtype=int16)
    i: i32
    j: i32
    for i in range(rows):
        for j in range(cols):
            D[i, j] = B[(i * cols) + j]
    return D