lcompilers / lpython

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

Uncaught assertion on legal code #1982

Open rebcabin opened 1 year ago

rebcabin commented 1 year ago

repro: https://github.com/rebcabin/lpython/tree/brian-lasr/lasr/LP-pycharm/Issue1982

The culprit seems to be this refactored function (it's crappy code, I know; PyCharm made it, but it's legal CPython!):

def eat_white_debug_dump(self : InOut[LasrLexer]):
    print('self.fd._len = ', end='');
    print(self.fd._len, end='');
    print('.')
    print('self.fd._0cursor = ', end='');
    print(self.fd._0cursor, end='');
    print('.')
    c: str = peek(self)
    print('eat-white line 175, c = "', end='')
    print(c, end='');
    print('".')
    print('self.fd._len = ', end='');
    print(self.fd._len, end='');
    print('.')
    print('self.fd._0cursor = ', end='');
    print(self.fd._0cursor, end='');
    print('.')
    return c

CPython:

(lp) ┌─(~/CLionProjects/lpython/lasr/LP-pycharm/Issue1982)───────────────────────────────────────────────────────────────────────────────────────────────(brian@Golf37:s000)─┐
└─(22:24:10 on brian-lasr ✭)──> PYTHONPATH='../../../src/runtime/lpython' python lasr_lexer.py                                                            ──(Tue,Jun20)─┘
STRINGIO TEST
READ-SEEK-TELL-TEST
LEXER TEST
self.fd._len = 12.
self.fd._0cursor = 0.
eat-white line 175, c = " ".
self.fd._len = 12.
self.fd._0cursor = 0.
12.
self.fd._0cursor = 0.
eat-white line 175, c = " ".
self.fd._len = 12.
self.fd._0cursor = 0.

LPython:

(lp) ┌─(~/CLionProjects/lpython/lasr/LP-pycharm/Issue1982)───────────────────────────────────────────────────────────────────────────────────────────────(brian@Golf37:s000)─┐
└─(22:22:53 on brian-lasr ✹ ✭)──> ~/CLionProjects/lpython/src/bin/lpython -I. lasr_lexer.py                                                               ──(Tue,Jun20)─┘
Internal Compiler Error: Unhandled exception
Traceback (most recent call last):
  File "/Users/brian/CLionProjects/lpython/src/bin/lpython.cpp", line 1844
    err = compile_python_to_object_file(arg_file, tmp_o, runtime_library_dir,
  File "/Users/brian/CLionProjects/lpython/src/bin/lpython.cpp", line 783
    r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options,
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 7499
    auto res2 = body_visitor(al, lm, *ast_m, diagnostics, unit, main_module,
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 7452
    b.visit_Module(ast);
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 4590
    visit_stmt(*x.m_body[i]);
  File "/Users/brian/CLionProjects/lpython/src/lpython/python_ast.h", line 1883
    void visit_stmt(const stmt_t &b) { visit_stmt_t(b, self()); }
  File "/Users/brian/CLionProjects/lpython/src/lpython/python_ast.h", line 1751
    case stmtType::FunctionDef: { v.visit_FunctionDef((const FunctionDef_t &)x); return; }
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 4697
    handle_fn(x, *f);
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 4679
    transform_stmts(body, x.n_body, x.m_body);
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 4550
    this->visit_stmt(*m_body[i]);
  File "/Users/brian/CLionProjects/lpython/src/lpython/python_ast.h", line 1883
    void visit_stmt(const stmt_t &b) { visit_stmt_t(b, self()); }
  File "/Users/brian/CLionProjects/lpython/src/lpython/python_ast.h", line 1757
    case stmtType::AugAssign: { v.visit_AugAssign((const AugAssign_t &)x); return; }
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 4823
    visit_AnnAssignUtil(x, var_name);
  File "/Users/brian/CLionProjects/lpython/src/lpython/semantics/python_ast_to_asr.cpp", line 2796
    value = ASRUtils::EXPR(tmp);
  File "/Users/brian/CLionProjects/lpython/src/libasr/asr_utils.h", line 34
    return ASR::down_cast<ASR::expr_t>(f);
  File "/Users/brian/CLionProjects/lpython/src/libasr/asr.h", line 41
    LCOMPILERS_ASSERT(is_a<T>(*f));
AssertFailed: is_a<T>(*f)
rebcabin commented 1 year ago

adding the return type of -> str to the suspect function produces intelligible error messages. I think LPython should say something like return type of None doesn't match type of return value "c" instead of throwing an assertion :)

rebcabin commented 1 year ago

This works:

def eat_white(self : InOut[LasrLexer]) -> None:
    c : str = eat_white_debug_dump(self)
    c = peek(self)
    while c != EOF_SIGNAL and in_(c, WHITESPACE):
        c = read(self.fd, 1)
        if c == NEWLINE:
            self.col = 1
            self.line += 1
        else:
            self.col += 1
        c = peek(self)

def eat_white_debug_dump(self : InOut[LasrLexer]) -> str:
    print('self.fd._len = ', end='');
    print(self.fd._len, end='');
    print('.')
    print('self.fd._0cursor = ', end='');
    print(self.fd._0cursor, end='');
    print('.')
    c: str = peek(self)
    print('eat-white line 175, c = "', end='')
    print(c, end='');
    print('".')
    print('self.fd._len = ', end='');
    print(self.fd._len, end='');
    print('.')
    print('self.fd._0cursor = ', end='');
    print(self.fd._0cursor, end='');
    print('.')
    return c
Smit-create commented 1 year ago

We do have an error message for mis-match return type:

def f():
    return "bug"

def g():
    x:str = f()
g()

This will give:

semantic error: Return type of function is not defined
 --> c.py:2:5
  |
2 |     return "bug"
  |     ^^^^^^^^^^^^

The main reason for failure in the code is because of this line: https://github.com/rebcabin/lpython/blob/77c8014cf215edc5d1fdd53561f8e1e683fee5ad/lasr/LP-pycharm/Issue1982/lasr_lexer.py#L175

Since, eat_white_debug_dump is returning None so it is a stmt node (because it is considered a Subroutine Call).

The reason it didn't throw the return type mismatch first was that Return is visited in body-visitor and so the check also comes from there, and, also function eat_white is visited first in body-visitor. If you declare the function eat_white_debug_dump above the function eat_white(so it gets visited first), then you get the following error:

semantic error: Return type of function is not defined
   --> a.py:190:5
    |
190 |     return c
    |     ^^^^^^^^ 
Smit-create commented 1 year ago

To show a good error message for this we may add a check over there to check if there's a Subroutine Call in the assignment throw an error saying the function doesn't return anything.