Skip to content

Commit 87ca4fe

Browse files
authored
Merge pull request #1203 from czgdp1807/const
Support `Const[...]` type annotation in LPython syntax (LLVM/C)
2 parents 4bc8bbd + e653003 commit 87ca4fe

18 files changed

+374
-52
lines changed

integration_tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ RUN(NAME exit_02c FAIL LABELS cpython llvm c)
154154
RUN(NAME print_01 LABELS cpython llvm c wasm) # wasm not yet supports sep and end keywords
155155

156156
# CPython and LLVM
157+
RUN(NAME const_01 LABELS cpython llvm c)
158+
RUN(NAME const_02 LABELS cpython llvm c)
157159
RUN(NAME expr_01 LABELS cpython llvm c wasm)
158160
RUN(NAME expr_02 LABELS cpython llvm c wasm)
159161
RUN(NAME expr_03 LABELS cpython llvm c wasm)

integration_tests/const_01.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from ltypes import Const, i32, i64, f32, f64
2+
3+
def test_const_variables():
4+
xci: Const[i32] = 0.0
5+
xi: i32 = 0
6+
7+
yci: Const[i64] = int(1)
8+
yi: i64 = int(1)
9+
10+
xcf: Const[f32] = 2
11+
xf: f32 = 2.0
12+
13+
ycf: Const[f64] = 3.0
14+
yf: f64 = 3.0
15+
16+
assert xci == xi
17+
assert yci == yi
18+
assert xcf == xf
19+
assert ycf == yf
20+
21+
test_const_variables()

integration_tests/const_02.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from ltypes import i32, f64, Const
2+
3+
def f(x: Const[i32]) -> i32:
4+
return x + 1
5+
6+
def g(x: Const[i32]) -> Const[f64]:
7+
return float(x + 2)
8+
9+
def h(x: i32) -> Const[i32]:
10+
return x + 3
11+
12+
def test_call_cases():
13+
y: i32 = 1
14+
yconst: Const[i32] = 4
15+
# argument const, parameter non-const
16+
print(h(yconst), f(y), g(yconst))
17+
assert h(yconst) == 7
18+
19+
# argument non-const, parameter const
20+
assert f(y) == 2
21+
22+
# argument const, parameter const
23+
assert g(yconst) == 6
24+
25+
def test_assign_cases():
26+
y: i32
27+
yconst: Const[i32] = 4
28+
# target const, value non-const - error case
29+
30+
# target non-const, value const
31+
y = g(yconst)
32+
print(y)
33+
assert y == 6.0
34+
35+
# target const, value const - error case
36+
37+
test_call_cases()
38+
test_assign_cases()

src/libasr/ASR.asdl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ ttype
343343
| Class(symbol class_type, dimension* dims)
344344
| Dict(ttype key_type, ttype value_type)
345345
| Pointer(ttype type)
346+
| Const(ttype type)
346347
| CPtr()
347348
| TypeParameter(identifier param, dimension* dims)
348349

src/libasr/asr_utils.h

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,33 @@ static inline ASR::ttype_t* symbol_type(const ASR::symbol_t *f)
105105
return nullptr;
106106
}
107107

108+
static inline ASR::ttype_t* get_contained_type(ASR::ttype_t* asr_type) {
109+
switch( asr_type->type ) {
110+
case ASR::ttypeType::List: {
111+
return ASR::down_cast<ASR::List_t>(asr_type)->m_type;
112+
}
113+
case ASR::ttypeType::Set: {
114+
return ASR::down_cast<ASR::Set_t>(asr_type)->m_type;
115+
}
116+
case ASR::ttypeType::Enum: {
117+
ASR::Enum_t* enum_asr = ASR::down_cast<ASR::Enum_t>(asr_type);
118+
ASR::EnumType_t* enum_type = ASR::down_cast<ASR::EnumType_t>(enum_asr->m_enum_type);
119+
return enum_type->m_type;
120+
}
121+
case ASR::ttypeType::Pointer: {
122+
ASR::Pointer_t* pointer_asr = ASR::down_cast<ASR::Pointer_t>(asr_type);
123+
return pointer_asr->m_type;
124+
}
125+
case ASR::ttypeType::Const: {
126+
ASR::Const_t* const_asr = ASR::down_cast<ASR::Const_t>(asr_type);
127+
return const_asr->m_type;
128+
}
129+
default: {
130+
return asr_type;
131+
}
132+
}
133+
}
134+
108135
static inline std::string type_to_str(const ASR::ttype_t *t)
109136
{
110137
switch (t->type) {
@@ -148,6 +175,10 @@ static inline std::string type_to_str(const ASR::ttype_t *t)
148175
return type_to_str(ASRUtils::type_get_past_pointer(
149176
const_cast<ASR::ttype_t*>(t))) + " pointer";
150177
}
178+
case ASR::ttypeType::Const: {
179+
return type_to_str(ASRUtils::get_contained_type(
180+
const_cast<ASR::ttype_t*>(t))) + " const";
181+
}
151182
case ASR::ttypeType::TypeParameter: {
152183
ASR::TypeParameter_t* tp = ASR::down_cast<ASR::TypeParameter_t>(t);
153184
return tp->m_param;
@@ -776,6 +807,13 @@ static inline std::string get_type_code(const ASR::ttype_t *t, bool use_undersco
776807
}
777808
return "Pointer[" + get_type_code(p->m_type, use_underscore_sep, encode_dimensions_) + "]";
778809
}
810+
case ASR::ttypeType::Const: {
811+
ASR::Const_t* p = ASR::down_cast<ASR::Const_t>(t);
812+
if( use_underscore_sep ) {
813+
return "Const_" + get_type_code(p->m_type, use_underscore_sep, encode_dimensions_) + "_";
814+
}
815+
return "Const[" + get_type_code(p->m_type, use_underscore_sep, encode_dimensions_) + "]";
816+
}
779817
default: {
780818
throw LCompilersException("Type encoding not implemented for "
781819
+ std::to_string(t->type));
@@ -877,6 +915,10 @@ static inline std::string type_to_str_python(const ASR::ttype_t *t,
877915
ASR::Pointer_t* p = ASR::down_cast<ASR::Pointer_t>(t);
878916
return "Pointer[" + type_to_str_python(p->m_type) + "]";
879917
}
918+
case ASR::ttypeType::Const: {
919+
ASR::Const_t* p = ASR::down_cast<ASR::Const_t>(t);
920+
return "Const[" + type_to_str_python(p->m_type) + "]";
921+
}
880922
case ASR::ttypeType::TypeParameter: {
881923
ASR::TypeParameter_t *p = ASR::down_cast<ASR::TypeParameter_t>(t);
882924
return p->m_param;
@@ -1202,6 +1244,10 @@ inline int extract_dimensions_from_ttype(ASR::ttype_t *x,
12021244
n_dims = extract_dimensions_from_ttype(ASR::down_cast<ASR::Pointer_t>(x)->m_type, m_dims);
12031245
break;
12041246
}
1247+
case ASR::ttypeType::Const: {
1248+
n_dims = extract_dimensions_from_ttype(ASR::down_cast<ASR::Const_t>(x)->m_type, m_dims);
1249+
break;
1250+
}
12051251
case ASR::ttypeType::List: {
12061252
n_dims = 0;
12071253
m_dims = nullptr;
@@ -1564,6 +1610,11 @@ inline bool check_equal_type(ASR::ttype_t* x, ASR::ttype_t* y) {
15641610
x = ASRUtils::type_get_past_pointer(x);
15651611
y = ASRUtils::type_get_past_pointer(y);
15661612
return check_equal_type(x, y);
1613+
} else if(ASR::is_a<ASR::Const_t>(*x) ||
1614+
ASR::is_a<ASR::Const_t>(*y)) {
1615+
x = ASRUtils::get_contained_type(x);
1616+
y = ASRUtils::get_contained_type(y);
1617+
return check_equal_type(x, y);
15671618
} else if (ASR::is_a<ASR::List_t>(*x) && ASR::is_a<ASR::List_t>(*y)) {
15681619
x = ASR::down_cast<ASR::List_t>(x)->m_type;
15691620
y = ASR::down_cast<ASR::List_t>(y)->m_type;
@@ -1637,29 +1688,6 @@ static inline bool is_dimension_empty(ASR::dimension_t* dims, size_t n) {
16371688
return false;
16381689
}
16391690

1640-
static inline ASR::ttype_t* get_contained_type(ASR::ttype_t* asr_type) {
1641-
switch( asr_type->type ) {
1642-
case ASR::ttypeType::List: {
1643-
return ASR::down_cast<ASR::List_t>(asr_type)->m_type;
1644-
}
1645-
case ASR::ttypeType::Set: {
1646-
return ASR::down_cast<ASR::Set_t>(asr_type)->m_type;
1647-
}
1648-
case ASR::ttypeType::Enum: {
1649-
ASR::Enum_t* enum_asr = ASR::down_cast<ASR::Enum_t>(asr_type);
1650-
ASR::EnumType_t* enum_type = ASR::down_cast<ASR::EnumType_t>(enum_asr->m_enum_type);
1651-
return enum_type->m_type;
1652-
}
1653-
case ASR::ttypeType::Pointer: {
1654-
ASR::Pointer_t* pointer_asr = ASR::down_cast<ASR::Pointer_t>(asr_type);
1655-
return pointer_asr->m_type;
1656-
}
1657-
default: {
1658-
return asr_type;
1659-
}
1660-
}
1661-
}
1662-
16631691
static inline ASR::ttype_t* get_type_parameter(ASR::ttype_t* t) {
16641692
switch (t->type) {
16651693
case ASR::ttypeType::TypeParameter: {

src/libasr/asr_verify.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class VerifyVisitor : public BaseWalkVisitor<VerifyVisitor>
4444
std::vector<std::string> function_dependencies;
4545
std::vector<std::string> module_dependencies;
4646

47+
std::set<std::pair<uint64_t, std::string>> const_assigned;
48+
4749
public:
4850
VerifyVisitor(bool check_external) : check_external{check_external} {}
4951

@@ -244,6 +246,23 @@ class VerifyVisitor : public BaseWalkVisitor<VerifyVisitor>
244246
current_symtab = parent_symtab;
245247
}
246248

249+
void visit_Assignment(const Assignment_t& x) {
250+
ASR::expr_t* target = x.m_target;
251+
ASR::ttype_t* target_type = ASRUtils::expr_type(target);
252+
if( ASR::is_a<ASR::Var_t>(*target) ) {
253+
ASR::Var_t* target_Var = ASR::down_cast<ASR::Var_t>(target);
254+
if( ASR::is_a<ASR::Const_t>(*target_type) ) {
255+
std::string variable_name = ASRUtils::symbol_name(target_Var->m_v);
256+
require(const_assigned.find(std::make_pair(current_symtab->counter,
257+
variable_name)) == const_assigned.end(),
258+
"Assignment target with " + ASRUtils::type_to_str_python(target_type)
259+
+ " cannot be re-assigned.");
260+
const_assigned.insert(std::make_pair(current_symtab->counter, variable_name));
261+
}
262+
}
263+
BaseWalkVisitor<VerifyVisitor>::visit_Assignment(x);
264+
}
265+
247266
void visit_Function(const Function_t &x) {
248267
function_dependencies.clear();
249268
function_dependencies.reserve(x.n_dependencies);

src/libasr/codegen/asr_to_c.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,18 @@ class ASRToCVisitor : public BaseCCPPVisitor<ASRToCVisitor>
528528
false, false);
529529
} else if (ASR::is_a<ASR::CPtr_t>(*v.m_type)) {
530530
sub = format_type_c("", "void*", v.m_name, false, false);
531+
} else if (ASR::is_a<ASR::Const_t>(*v.m_type)) {
532+
if( v.m_intent == ASRUtils::intent_local ) {
533+
LFORTRAN_ASSERT(v.m_symbolic_value);
534+
visit_expr(*v.m_symbolic_value);
535+
sub = "#define " + std::string(v.m_name) + " " + src + "\n";
536+
return sub;
537+
} else {
538+
std::string const_underlying_type = get_c_type_from_ttype_t(
539+
ASR::down_cast<ASR::Const_t>(v.m_type)->m_type);
540+
sub = format_type_c("", "const " + const_underlying_type + " ",
541+
v.m_name, false, false);
542+
}
531543
} else if (ASR::is_a<ASR::Enum_t>(*v.m_type)) {
532544
ASR::Enum_t* enum_ = ASR::down_cast<ASR::Enum_t>(v.m_type);
533545
ASR::EnumType_t* enum_type = ASR::down_cast<ASR::EnumType_t>(enum_->m_enum_type);
@@ -620,7 +632,11 @@ R"(
620632
for (auto &item : x.m_global_scope->get_scope()) {
621633
if (ASR::is_a<ASR::Variable_t>(*item.second)) {
622634
ASR::Variable_t *v = ASR::down_cast<ASR::Variable_t>(item.second);
623-
unit_src += convert_variable_decl(*v) + ";\n";
635+
unit_src += convert_variable_decl(*v);
636+
if( !ASR::is_a<ASR::Const_t>(*v->m_type) ||
637+
v->m_intent == ASRUtils::intent_return_var ) {
638+
unit_src += ";\n";
639+
}
624640
}
625641
}
626642

@@ -736,7 +752,11 @@ R"(
736752
if (ASR::is_a<ASR::Variable_t>(*item.second)) {
737753
ASR::Variable_t *v = ASR::down_cast<ASR::Variable_t>(item.second);
738754
decl += indent1;
739-
decl += convert_variable_decl(*v) + ";\n";
755+
decl += convert_variable_decl(*v);
756+
if( !ASR::is_a<ASR::Const_t>(*v->m_type) ||
757+
v->m_intent == ASRUtils::intent_return_var ) {
758+
decl += ";\n";
759+
}
740760
}
741761
}
742762

@@ -765,7 +785,11 @@ R"(
765785
body += indent + convert_variable_decl(
766786
*ASR::down_cast<ASR::Variable_t>(member),
767787
false,
768-
(c_type_name != "union")) + ";\n";
788+
(c_type_name != "union"));
789+
if( !ASR::is_a<ASR::Const_t>(*ASRUtils::symbol_type(member)) ||
790+
ASR::down_cast<ASR::Variable_t>(member)->m_intent == ASRUtils::intent_return_var ) {
791+
body += ";\n";
792+
}
769793
}
770794
indentation_level -= 1;
771795
std::string end_struct = "};\n\n";
@@ -976,6 +1000,10 @@ R"(
9761000
ASR::ttype_t* enum_underlying_type = ASRUtils::get_contained_type(t);
9771001
return get_print_type(enum_underlying_type, deref_ptr);
9781002
}
1003+
case ASR::ttypeType::Const: {
1004+
ASR::ttype_t* const_underlying_type = ASRUtils::get_contained_type(t);
1005+
return get_print_type(const_underlying_type, deref_ptr);
1006+
}
9791007
default : throw LCompilersException("Not implemented");
9801008
}
9811009
}

src/libasr/codegen/asr_to_c_cpp.h

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,11 @@ R"(#include <stdio.h>
644644
for (auto &item : x.m_symtab->get_scope()) {
645645
if (ASR::is_a<ASR::Variable_t>(*item.second)) {
646646
ASR::Variable_t *v = ASR::down_cast<ASR::Variable_t>(item.second);
647-
decl += self().convert_variable_decl(*v) + ";\n";
647+
decl += self().convert_variable_decl(*v);
648+
if( !ASR::is_a<ASR::Const_t>(*v->m_type) ||
649+
v->m_intent == ASRUtils::intent_return_var ) {
650+
decl += ";\n";
651+
}
648652
}
649653
}
650654

@@ -674,7 +678,11 @@ R"(#include <stdio.h>
674678
for (auto &item : block->m_symtab->get_scope()) {
675679
if (ASR::is_a<ASR::Variable_t>(*item.second)) {
676680
ASR::Variable_t *v = ASR::down_cast<ASR::Variable_t>(item.second);
677-
decl += indent + self().convert_variable_decl(*v) + ";\n";
681+
decl += indent + self().convert_variable_decl(*v);
682+
if( !ASR::is_a<ASR::Const_t>(*v->m_type) ||
683+
v->m_intent == ASRUtils::intent_return_var ) {
684+
decl += ";\n";
685+
}
678686
}
679687
}
680688
for (size_t i=0; i<block->n_body; i++) {
@@ -742,6 +750,10 @@ R"(#include <stdio.h>
742750
ASR::List_t* list_type = ASR::down_cast<ASR::List_t>(return_var->m_type);
743751
std::string list_element_type = get_c_type_from_ttype_t(list_type->m_type);
744752
sub = list_api->get_list_type(list_type, list_element_type) + " ";
753+
} else if (ASR::is_a<ASR::Const_t>(*return_var->m_type)) {
754+
ASR::Const_t* const_type = ASR::down_cast<ASR::Const_t>(return_var->m_type);
755+
std::string const_type_str = get_c_type_from_ttype_t(const_type->m_type);
756+
sub = "const " + const_type_str + " ";
745757
} else {
746758
throw CodeGenError("Return type not supported in function '" +
747759
std::string(x.m_name) +
@@ -832,7 +844,11 @@ R"(#include <stdio.h>
832844
if (ASR::is_a<ASR::Variable_t>(*item.second)) {
833845
ASR::Variable_t *v = ASR::down_cast<ASR::Variable_t>(item.second);
834846
if (v->m_intent == LFortran::ASRUtils::intent_local || v->m_intent == LFortran::ASRUtils::intent_return_var) {
835-
decl += indent + self().convert_variable_decl(*v) + ";\n";
847+
decl += indent + self().convert_variable_decl(*v);
848+
if( !ASR::is_a<ASR::Const_t>(*v->m_type) ||
849+
v->m_intent == ASRUtils::intent_return_var ) {
850+
decl += ";\n";
851+
}
836852
}
837853
}
838854
}
@@ -980,6 +996,10 @@ R"(#include <stdio.h>
980996
void visit_Assignment(const ASR::Assignment_t &x) {
981997
std::string target;
982998
ASR::ttype_t* m_target_type = ASRUtils::expr_type(x.m_target);
999+
if( ASR::is_a<ASR::Const_t>(*m_target_type) ) {
1000+
src = "";
1001+
return ;
1002+
}
9831003
ASR::ttype_t* m_value_type = ASRUtils::expr_type(x.m_value);
9841004
bool is_target_list = ASR::is_a<ASR::List_t>(*m_target_type);
9851005
bool is_value_list = ASR::is_a<ASR::List_t>(*m_value_type);

0 commit comments

Comments
 (0)