From 5148356a11b5200b7db7c6302ff61b76e42e2264 Mon Sep 17 00:00:00 2001 From: Gagandeep Singh Date: Fri, 21 Apr 2023 23:16:16 +0530 Subject: [PATCH] Handle arguments of ``sizeof`` by distinguishing ``ttype`` and ``expr`` (#1733) --- integration_tests/CMakeLists.txt | 1 + integration_tests/sizeof_02.py | 10 +++ integration_tests/sizeof_02_module.py | 6 ++ src/lpython/semantics/python_ast_to_asr.cpp | 70 ++++++++++++++------- 4 files changed, 63 insertions(+), 24 deletions(-) create mode 100644 integration_tests/sizeof_02.py create mode 100644 integration_tests/sizeof_02_module.py diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 47579c8162..a2c299e0b3 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -463,6 +463,7 @@ RUN(NAME structs_20 LABELS cpython llvm c RUN(NAME structs_21 LABELS cpython llvm c) RUN(NAME sizeof_01 LABELS llvm c EXTRAFILES sizeof_01b.c) +RUN(NAME sizeof_02 LABELS cpython llvm c) RUN(NAME enum_01 LABELS cpython llvm c) RUN(NAME enum_02 LABELS cpython llvm) RUN(NAME enum_03 LABELS cpython llvm c) diff --git a/integration_tests/sizeof_02.py b/integration_tests/sizeof_02.py new file mode 100644 index 0000000000..40d34af64c --- /dev/null +++ b/integration_tests/sizeof_02.py @@ -0,0 +1,10 @@ +from sizeof_02_module import A +from lpython import i64, sizeof + +def get_sizeof() -> i64: + return sizeof(A) + +def test(): + print(get_sizeof()) + +test() diff --git a/integration_tests/sizeof_02_module.py b/integration_tests/sizeof_02_module.py new file mode 100644 index 0000000000..19aeb73705 --- /dev/null +++ b/integration_tests/sizeof_02_module.py @@ -0,0 +1,6 @@ +from lpython import i32, f32, dataclass + +@dataclass +class A: + x: i32 + y: f32 diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 2968f70770..145d8b2732 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -905,7 +905,8 @@ class CommonVisitor : public AST::BaseVisitor { ASR::ttype_t* get_type_from_var_annotation(std::string var_annotation, const Location& loc, Vec& dims, - AST::expr_t** m_args=nullptr, size_t n_args=0) { + AST::expr_t** m_args=nullptr, size_t n_args=0, + bool raise_error=true) { ASR::ttype_t* type = nullptr; if (var_annotation == "i8") { type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, @@ -967,7 +968,9 @@ class CommonVisitor : public AST::BaseVisitor { } } } - throw SemanticError("Unsupported type annotation: " + var_annotation, loc); + if( raise_error ) { + throw SemanticError("Unsupported type annotation: " + var_annotation, loc); + } } return type; } @@ -1486,7 +1489,8 @@ class CommonVisitor : public AST::BaseVisitor { // Examples: // i32, i64, f32, f64 // f64[256], i32[:] - ASR::ttype_t * ast_expr_to_asr_type(const Location &loc, const AST::expr_t &annotation) { + ASR::ttype_t * ast_expr_to_asr_type(const Location &loc, const AST::expr_t &annotation, + bool raise_error=true) { Vec dims; dims.reserve(al, 4); AST::expr_t** m_args = nullptr; size_t n_args = 0; @@ -1630,7 +1634,7 @@ class CommonVisitor : public AST::BaseVisitor { loc); } - return get_type_from_var_annotation(var_annotation, annotation.base.loc, dims, m_args, n_args); + return get_type_from_var_annotation(var_annotation, annotation.base.loc, dims, m_args, n_args, raise_error); } ASR::expr_t *index_add_one(const Location &loc, ASR::expr_t *idx) { @@ -6323,12 +6327,13 @@ class BodyVisitor : public CommonVisitor { return ; } // Keyword arguments handled in make_call_helper - if( x.n_keywords == 0 ) { - args.reserve(al, x.n_args); - visit_expr_list(x.m_args, x.n_args, args); - } + #define parse_args() if( x.n_keywords == 0 ) { \ + args.reserve(al, x.n_args); \ + visit_expr_list(x.m_args, x.n_args, args); \ + } \ if (AST::is_a(*x.m_func)) { + parse_args() AST::Attribute_t *at = AST::down_cast(x.m_func); if (AST::is_a(*at->m_value)) { AST::Name_t *n = AST::down_cast(at->m_value); @@ -6511,6 +6516,7 @@ class BodyVisitor : public CommonVisitor { tmp = nullptr; return; } else if (call_name == "callable") { + parse_args() if (args.size() != 1) { throw SemanticError(call_name + "() takes exactly one argument (" + std::to_string(args.size()) + " given)", x.base.base.loc); @@ -6526,11 +6532,13 @@ class BodyVisitor : public CommonVisitor { tmp = ASR::make_LogicalConstant_t(al, x.base.base.loc, result, type); return; } else if( call_name == "pointer" ) { + parse_args() ASR::ttype_t *type = ASRUtils::TYPE(ASR::make_Pointer_t(al, x.base.base.loc, ASRUtils::expr_type(args[0].m_value))); tmp = ASR::make_GetPointer_t(al, x.base.base.loc, args[0].m_value, type, nullptr); return ; } else if( call_name == "array" ) { + parse_args() if( args.size() != 1 ) { throw SemanticError("array accepts only 1 argument for now, got " + std::to_string(args.size()) + " arguments instead.", @@ -6550,6 +6558,7 @@ class BodyVisitor : public CommonVisitor { } return; } else if( call_name == "deepcopy" ) { + parse_args() if( args.size() != 1 ) { throw SemanticError("deepcopy only accepts one argument, found " + std::to_string(args.size()) + " instead.", @@ -6558,27 +6567,36 @@ class BodyVisitor : public CommonVisitor { tmp = (ASR::asr_t*) args[0].m_value; return ; } else if( call_name == "sizeof" ) { - if( args.size() != 1 ) { + + if( x.n_args + x.n_keywords != 1 ) { throw SemanticError("sizeof only accepts one argument, found " + - std::to_string(args.size()) + " instead.", + std::to_string(x.n_args + x.n_keywords) + " instead.", x.base.base.loc); } - ASR::ttype_t* arg_type = nullptr; - if( ASR::is_a(*args[0].m_value) ) { - ASR::Var_t* arg_Var = ASR::down_cast(args[0].m_value); - if( ASR::is_a(*arg_Var->m_v) ) { - arg_type = ASR::down_cast(arg_Var->m_v)->m_type; - } else if( ASR::is_a(*arg_Var->m_v) ) { - arg_type = ASRUtils::TYPE(ASR::make_Struct_t(al, x.base.base.loc, - arg_Var->m_v, nullptr, 0)); - } else { - throw SemanticError("Symbol " + std::to_string(arg_Var->m_v->type) + - " is not yet supported in sizeof.", - x.base.base.loc); + ASR::ttype_t* arg_type = ast_expr_to_asr_type(x.base.base.loc, *x.m_args[0], false); + ASR::expr_t* arg = nullptr; + if( !arg_type ) { + visit_expr(*x.m_args[0]); + arg = ASRUtils::EXPR(tmp); + } + if( arg ) { + if( ASR::is_a(*arg) ) { + ASR::Var_t* arg_Var = ASR::down_cast(arg); + ASR::symbol_t* arg_Var_m_v = ASRUtils::symbol_get_past_external(arg_Var->m_v); + if( ASR::is_a(*arg_Var_m_v) ) { + // TODO: Import the underlying struct if arg_type is of Struct type + // Ideally if a variable of struct type is being imported then its underlying type + // should also be imported automatically. However, the naming of the + // underlying struct type might lead to collisions, so importing the type + // here seems like a better choice. Should be done later when the case arises. + arg_type = ASR::down_cast(arg_Var_m_v)->m_type; + } else { + throw SemanticError("Symbol " + std::to_string(arg_Var_m_v->type) + + " is not yet supported in sizeof.", + x.base.base.loc); + } } - } else { - arg_type = ASRUtils::expr_type(args[0].m_value); } ASR::ttype_t* size_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc, 8, nullptr, 0)); @@ -6588,6 +6606,7 @@ class BodyVisitor : public CommonVisitor { } else if( call_name == "f64" || call_name == "f32" || call_name == "i64" || call_name == "i32" || call_name == "c32" || call_name == "c64" || call_name == "i8" || call_name == "i16" ) { + parse_args() ASR::ttype_t* target_type = nullptr; if( call_name == "i8" ) { target_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc, 1, nullptr, 0)); @@ -6611,6 +6630,7 @@ class BodyVisitor : public CommonVisitor { tmp = (ASR::asr_t*) arg; return ; } else if (intrinsic_node_handler.is_present(call_name)) { + parse_args() tmp = intrinsic_node_handler.get_intrinsic_node(call_name, al, x.base.base.loc, args); return; @@ -6621,6 +6641,8 @@ class BodyVisitor : public CommonVisitor { } } // end of "comment" } + + parse_args() tmp = make_call_helper(al, s, current_scope, args, call_name, x.base.base.loc, false, x.m_args, x.n_args, x.m_keywords, x.n_keywords); }