diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 44b703eaeb..a396205a23 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -551,6 +551,7 @@ RUN(NAME test_list_pop3 LABELS cpython llvm) RUN(NAME test_list_compare LABELS cpython llvm) RUN(NAME test_list_concat LABELS cpython llvm c NOFAST) RUN(NAME test_list_reserve LABELS cpython llvm) +RUN(NAME test_const_list LABELS cpython llvm) RUN(NAME test_tuple_01 LABELS cpython llvm c) RUN(NAME test_tuple_02 LABELS cpython llvm c NOFAST) RUN(NAME test_tuple_03 LABELS cpython llvm c) diff --git a/integration_tests/test_const_list.py b/integration_tests/test_const_list.py new file mode 100644 index 0000000000..4f0a568251 --- /dev/null +++ b/integration_tests/test_const_list.py @@ -0,0 +1,19 @@ +from lpython import i32, Const + + +def test_const_list(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + print(CONST_INTEGER_LIST.count(1)) + print(CONST_INTEGER_LIST.index(1)) + assert CONST_INTEGER_LIST.count(1) == 2 + assert CONST_INTEGER_LIST.index(1) == 0 + + CONST_STRING_LIST: Const[list[str]] = ["ALPHA", "BETA", "RELEASE"] + print(CONST_STRING_LIST.count("ALPHA")) + print(CONST_STRING_LIST.index("RELEASE")) + assert CONST_STRING_LIST.count("ALPHA") == 1 + assert CONST_STRING_LIST.index("RELEASE") == 2 + + +test_const_list() diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index d5af2946f7..8032a9f956 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -1729,7 +1729,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_ListCount(const ASR::ListCount_t& x) { - ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_arg)); + ASR::ttype_t *asr_el_type = ASRUtils::get_contained_type(ASRUtils::type_get_past_const(ASRUtils::expr_type(x.m_arg))); int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_arg); @@ -1744,7 +1744,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void generate_ListIndex(ASR::expr_t* m_arg, ASR::expr_t* m_ele, ASR::expr_t* m_start=nullptr, ASR::expr_t* m_end=nullptr) { - ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(m_arg)); + ASR::ttype_t *asr_el_type = ASRUtils::get_contained_type(ASRUtils::type_get_past_const(ASRUtils::expr_type(m_arg))); int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*m_arg); @@ -3514,7 +3514,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } } if( init_expr != nullptr && - !ASR::is_a(*v->m_type)) { + !is_list) { target_var = ptr; tmp = nullptr; if (v->m_value != nullptr) { @@ -3590,7 +3590,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor throw CodeGenError("Unsupported len value in ASR"); } } else if (is_list) { - ASR::List_t* asr_list = ASR::down_cast(v->m_type); + ASR::List_t* asr_list = ASR::down_cast( + ASRUtils::type_get_past_const(v->m_type)); std::string type_code = ASRUtils::get_type_code(asr_list->m_type); list_api->list_init(type_code, ptr, *module); } diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index 2fca01651d..340d61b999 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -2520,12 +2520,13 @@ namespace ListIndex { static inline void verify_args(const ASR::IntrinsicScalarFunction_t& x, diag::Diagnostics& diagnostics) { ASRUtils::require_impl(x.n_args <= 4, "Call to list.index must have at most four arguments", x.base.base.loc, diagnostics); - ASRUtils::require_impl(ASR::is_a(*ASRUtils::expr_type(x.m_args[0])) && + ASR::ttype_t *list_type = ASRUtils::type_get_past_const(ASRUtils::expr_type(x.m_args[0])); + ASRUtils::require_impl(ASR::is_a(*list_type) && ASRUtils::check_equal_type(ASRUtils::expr_type(x.m_args[1]), - ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_args[0]))), + ASRUtils::get_contained_type(list_type)), "First argument to list.index must be of list type and " "second argument must be of same type as list elemental type", - x.base.base.loc, diagnostics); + x.base.base.loc, diagnostics); if(x.n_args >= 3) { ASRUtils::require_impl( ASR::is_a(*ASRUtils::expr_type(x.m_args[2])), @@ -2555,7 +2556,7 @@ static inline ASR::asr_t* create_ListIndex(Allocator& al, const Location& loc, const std::function err) { int64_t overload_id = 0; ASR::expr_t* list_expr = args[0]; - ASR::ttype_t *type = ASRUtils::expr_type(list_expr); + ASR::ttype_t *type = ASRUtils::type_get_past_const(ASRUtils::expr_type(list_expr)); ASR::ttype_t *list_type = ASR::down_cast(type)->m_type; ASR::ttype_t *ele_type = ASRUtils::expr_type(args[1]); if (!ASRUtils::check_equal_type(ele_type, list_type)) { diff --git a/src/lpython/semantics/python_attribute_eval.h b/src/lpython/semantics/python_attribute_eval.h index 1aab45b379..5c80074e01 100644 --- a/src/lpython/semantics/python_attribute_eval.h +++ b/src/lpython/semantics/python_attribute_eval.h @@ -67,7 +67,7 @@ struct AttributeHandler { ASR::asr_t* get_attribute(ASR::expr_t *e, std::string attr_name, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics &diag) { - ASR::ttype_t *type = ASRUtils::expr_type(e); + ASR::ttype_t *type = ASRUtils::type_get_past_const(ASRUtils::expr_type(e)); std::string class_name = get_type_name(type); if (class_name == "") { throw SemanticError("Type name is not implemented yet.", loc); @@ -124,6 +124,9 @@ struct AttributeHandler { static ASR::asr_t* eval_list_append(ASR::expr_t *s, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics &diag) { + if (ASR::is_a(*ASRUtils::expr_type(s))) { + throw SemanticError("cannot append element to a const list", loc); + } if (args.size() != 1) { throw SemanticError("append() takes exactly one argument", loc); @@ -148,6 +151,9 @@ struct AttributeHandler { static ASR::asr_t* eval_list_remove(ASR::expr_t *s, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics &diag) { + if (ASR::is_a(*ASRUtils::expr_type(s))) { + throw SemanticError("cannot remove element from a const list", loc); + } if (args.size() != 1) { throw SemanticError("remove() takes exactly one argument", loc); @@ -176,7 +182,7 @@ struct AttributeHandler { throw SemanticError("count() takes exactly one argument", loc); } - ASR::ttype_t *type = ASRUtils::expr_type(s); + ASR::ttype_t *type = ASRUtils::type_get_past_const(ASRUtils::expr_type(s)); ASR::ttype_t *list_type = ASR::down_cast(type)->m_type; ASR::ttype_t *ele_type = ASRUtils::expr_type(args[0]); if (!ASRUtils::check_equal_type(ele_type, list_type)) { @@ -211,6 +217,9 @@ struct AttributeHandler { static ASR::asr_t* eval_list_reverse(ASR::expr_t *s, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics &/*diag*/) { + if (ASR::is_a(*ASRUtils::expr_type(s))) { + throw SemanticError("cannot reverse a const list", loc); + } Vec args_with_list; args_with_list.reserve(al, args.size() + 1); args_with_list.push_back(al, s); @@ -225,6 +234,9 @@ struct AttributeHandler { static ASR::asr_t* eval_list_pop(ASR::expr_t *s, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics &/*diag*/) { + if (ASR::is_a(*ASRUtils::expr_type(s))) { + throw SemanticError("cannot pop element from a const list", loc); + } Vec args_with_list; args_with_list.reserve(al, args.size() + 1); args_with_list.push_back(al, s); @@ -239,6 +251,9 @@ struct AttributeHandler { static ASR::asr_t* eval_list_insert(ASR::expr_t *s, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics &diag) { + if (ASR::is_a(*ASRUtils::expr_type(s))) { + throw SemanticError("cannot insert element in a const list", loc); + } if (args.size() != 2) { throw SemanticError("insert() takes exactly two arguments", loc); @@ -270,6 +285,9 @@ struct AttributeHandler { static ASR::asr_t* eval_list_clear(ASR::expr_t *s, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics & diag) { + if (ASR::is_a(*ASRUtils::expr_type(s))) { + throw SemanticError("cannot clear elements from a const list", loc); + } if (args.size() != 0) { diag.add(diag::Diagnostic( "Incorrect number of arguments in 'clear', it accepts no argument", diff --git a/tests/errors/test_const_list_append.py b/tests/errors/test_const_list_append.py new file mode 100644 index 0000000000..c0c8e50e43 --- /dev/null +++ b/tests/errors/test_const_list_append.py @@ -0,0 +1,10 @@ +from lpython import i32, list, Const + + +def test_const_list_append(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + CONST_INTEGER_LIST.append(6) + + +test_const_list_append() diff --git a/tests/errors/test_const_list_clear.py b/tests/errors/test_const_list_clear.py new file mode 100644 index 0000000000..e233606f10 --- /dev/null +++ b/tests/errors/test_const_list_clear.py @@ -0,0 +1,10 @@ +from lpython import i32, list, Const + + +def test_const_list_clear(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + CONST_INTEGER_LIST.clear() + + +test_const_list_clear() diff --git a/tests/errors/test_const_list_insert.py b/tests/errors/test_const_list_insert.py new file mode 100644 index 0000000000..72f8b51e55 --- /dev/null +++ b/tests/errors/test_const_list_insert.py @@ -0,0 +1,10 @@ +from lpython import i32, list, Const + + +def test_const_list_insert(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + CONST_INTEGER_LIST.insert(3, 8) + + +test_const_list_insert() diff --git a/tests/errors/test_const_list_pop.py b/tests/errors/test_const_list_pop.py new file mode 100644 index 0000000000..fa405a7bc6 --- /dev/null +++ b/tests/errors/test_const_list_pop.py @@ -0,0 +1,10 @@ +from lpython import i32, list, Const + + +def test_const_list_pop(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + CONST_INTEGER_LIST.pop() + + +test_const_list_pop() diff --git a/tests/errors/test_const_list_remove.py b/tests/errors/test_const_list_remove.py new file mode 100644 index 0000000000..6073eef00c --- /dev/null +++ b/tests/errors/test_const_list_remove.py @@ -0,0 +1,10 @@ +from lpython import i32, list, Const + + +def test_const_list_remove(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + CONST_INTEGER_LIST.remove(1) + + +test_const_list_remove() diff --git a/tests/errors/test_const_list_reverse.py b/tests/errors/test_const_list_reverse.py new file mode 100644 index 0000000000..f1436b04ac --- /dev/null +++ b/tests/errors/test_const_list_reverse.py @@ -0,0 +1,10 @@ +from lpython import i32, list, Const + + +def test_const_list_reverse(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + CONST_INTEGER_LIST.reverse() + + +test_const_list_reverse() \ No newline at end of file diff --git a/tests/reference/asr-test_const_list_append-ada1ade.json b/tests/reference/asr-test_const_list_append-ada1ade.json new file mode 100644 index 0000000000..484830324d --- /dev/null +++ b/tests/reference/asr-test_const_list_append-ada1ade.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-test_const_list_append-ada1ade", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/test_const_list_append.py", + "infile_hash": "1f8e9cdfaf24139c23d0a063fcce8c1765b0349500874c946c2a5bda", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-test_const_list_append-ada1ade.stderr", + "stderr_hash": "84fe0a7a75edd73700bce92d3e43cdc85e7f3c58f0047f53fb4412ad", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-test_const_list_append-ada1ade.stderr b/tests/reference/asr-test_const_list_append-ada1ade.stderr new file mode 100644 index 0000000000..08b7bf6c6b --- /dev/null +++ b/tests/reference/asr-test_const_list_append-ada1ade.stderr @@ -0,0 +1,5 @@ +semantic error: cannot append element to a const list + --> tests/errors/test_const_list_append.py:7:5 + | +7 | CONST_INTEGER_LIST.append(6) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/reference/asr-test_const_list_clear-33bfae7.json b/tests/reference/asr-test_const_list_clear-33bfae7.json new file mode 100644 index 0000000000..a4ac6699f7 --- /dev/null +++ b/tests/reference/asr-test_const_list_clear-33bfae7.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-test_const_list_clear-33bfae7", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/test_const_list_clear.py", + "infile_hash": "df04c8c3b9063bbbe0a24443f962c70732fecef59a7418cd7d5182af", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-test_const_list_clear-33bfae7.stderr", + "stderr_hash": "5c0c698319211c447c76e3309a027ee068dffded22d87bb3024cedf9", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-test_const_list_clear-33bfae7.stderr b/tests/reference/asr-test_const_list_clear-33bfae7.stderr new file mode 100644 index 0000000000..89fc62b51a --- /dev/null +++ b/tests/reference/asr-test_const_list_clear-33bfae7.stderr @@ -0,0 +1,5 @@ +semantic error: cannot clear elements from a const list + --> tests/errors/test_const_list_clear.py:7:5 + | +7 | CONST_INTEGER_LIST.clear() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/reference/asr-test_const_list_insert-4c81295.json b/tests/reference/asr-test_const_list_insert-4c81295.json new file mode 100644 index 0000000000..6113030e62 --- /dev/null +++ b/tests/reference/asr-test_const_list_insert-4c81295.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-test_const_list_insert-4c81295", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/test_const_list_insert.py", + "infile_hash": "d4a31ff954a49f096c46e38118ab88ac8821d5d691f1ada9ab323828", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-test_const_list_insert-4c81295.stderr", + "stderr_hash": "148e2a44028dd423007236ebf7a2c393fcefa4e8c12aad565f1c87fe", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-test_const_list_insert-4c81295.stderr b/tests/reference/asr-test_const_list_insert-4c81295.stderr new file mode 100644 index 0000000000..0a416adfd3 --- /dev/null +++ b/tests/reference/asr-test_const_list_insert-4c81295.stderr @@ -0,0 +1,5 @@ +semantic error: cannot insert element in a const list + --> tests/errors/test_const_list_insert.py:7:5 + | +7 | CONST_INTEGER_LIST.insert(3, 8) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/reference/asr-test_const_list_pop-568b207.json b/tests/reference/asr-test_const_list_pop-568b207.json new file mode 100644 index 0000000000..eb4e398c99 --- /dev/null +++ b/tests/reference/asr-test_const_list_pop-568b207.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-test_const_list_pop-568b207", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/test_const_list_pop.py", + "infile_hash": "e6cae5dc10a6a3505b3227d8492f32859f5baef086c143b1afcacdbf", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-test_const_list_pop-568b207.stderr", + "stderr_hash": "32d57cbb983509ca6c54bc0812c9a74b3c1886ecc94e635c5011c378", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-test_const_list_pop-568b207.stderr b/tests/reference/asr-test_const_list_pop-568b207.stderr new file mode 100644 index 0000000000..ad22224de1 --- /dev/null +++ b/tests/reference/asr-test_const_list_pop-568b207.stderr @@ -0,0 +1,5 @@ +semantic error: cannot pop element from a const list + --> tests/errors/test_const_list_pop.py:7:5 + | +7 | CONST_INTEGER_LIST.pop() + | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/reference/asr-test_const_list_remove-c5deb20.json b/tests/reference/asr-test_const_list_remove-c5deb20.json new file mode 100644 index 0000000000..4abd87a66b --- /dev/null +++ b/tests/reference/asr-test_const_list_remove-c5deb20.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-test_const_list_remove-c5deb20", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/test_const_list_remove.py", + "infile_hash": "e2bfdbf86ced2fae5e85037b6ea8479c1b73ab9b11b21c259739f8c1", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-test_const_list_remove-c5deb20.stderr", + "stderr_hash": "3529d822548d9327dbd0eab32aebc7b4a0da518cc0a6c2356e65c7b8", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-test_const_list_remove-c5deb20.stderr b/tests/reference/asr-test_const_list_remove-c5deb20.stderr new file mode 100644 index 0000000000..cdc585f4fc --- /dev/null +++ b/tests/reference/asr-test_const_list_remove-c5deb20.stderr @@ -0,0 +1,5 @@ +semantic error: cannot remove element from a const list + --> tests/errors/test_const_list_remove.py:7:5 + | +7 | CONST_INTEGER_LIST.remove(1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/reference/asr-test_const_list_reverse-2df1a6f.json b/tests/reference/asr-test_const_list_reverse-2df1a6f.json new file mode 100644 index 0000000000..b463e10677 --- /dev/null +++ b/tests/reference/asr-test_const_list_reverse-2df1a6f.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-test_const_list_reverse-2df1a6f", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/test_const_list_reverse.py", + "infile_hash": "b49f332d26356501f60c0342b86303deb62cd13621a821f3f2bc30c9", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-test_const_list_reverse-2df1a6f.stderr", + "stderr_hash": "78d4df28bbde66600867165e7c4d2b7e56874ba0f459052f8ab1b7fc", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-test_const_list_reverse-2df1a6f.stderr b/tests/reference/asr-test_const_list_reverse-2df1a6f.stderr new file mode 100644 index 0000000000..f49888969e --- /dev/null +++ b/tests/reference/asr-test_const_list_reverse-2df1a6f.stderr @@ -0,0 +1,5 @@ +semantic error: cannot reverse a const list + --> tests/errors/test_const_list_reverse.py:7:5 + | +7 | CONST_INTEGER_LIST.reverse() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/tests.toml b/tests/tests.toml index ea687ca0b0..bc1a4d6fcb 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -828,6 +828,30 @@ asr = true filename = "errors/test_list_slicing.py" asr = true +[[test]] +filename = "errors/test_const_list_append.py" +asr = true + +[[test]] +filename = "errors/test_const_list_clear.py" +asr = true + +[[test]] +filename = "errors/test_const_list_insert.py" +asr = true + +[[test]] +filename = "errors/test_const_list_pop.py" +asr = true + +[[test]] +filename = "errors/test_const_list_reverse.py" +asr = true + +[[test]] +filename = "errors/test_const_list_remove.py" +asr = true + [[test]] filename = "errors/test_annassign_01.py" asr = true