Skip to content

Commit 0001e55

Browse files
authored
Merge pull request #2189 from Shaikh-Ubaid/unsigned_ints
Unsigned integers no wrap II
2 parents 4339407 + 4629fc7 commit 0001e55

19 files changed

+149
-60
lines changed

integration_tests/CMakeLists.txt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -570,11 +570,9 @@ RUN(NAME test_unary_op_01 LABELS cpython llvm c) # unary minus
570570
RUN(NAME test_unary_op_02 LABELS cpython llvm c) # unary plus
571571
RUN(NAME test_unary_op_03 LABELS cpython llvm c wasm) # unary bitinvert
572572
RUN(NAME test_unary_op_04 LABELS cpython llvm c) # unary bitinvert
573-
# Unsigned unary minus is not supported in CPython
574-
# RUN(NAME test_unary_op_05 LABELS cpython llvm c) # unsigned unary minus, plus
573+
RUN(NAME test_unary_op_05 LABELS cpython llvm c) # unsigned unary minus, plus
575574
RUN(NAME test_unary_op_06 LABELS cpython llvm c) # unsigned unary bitnot
576-
# The value after shift overflows in CPython
577-
# RUN(NAME test_unsigned_01 LABELS cpython llvm c) # unsigned bitshift left, right
575+
RUN(NAME test_unsigned_01 LABELS cpython llvm c) # unsigned bitshift left, right
578576
RUN(NAME test_unsigned_02 LABELS cpython llvm c)
579577
RUN(NAME test_unsigned_03 LABELS cpython llvm c)
580578
RUN(NAME test_bool_binop LABELS cpython llvm c)

integration_tests/cast_02.py

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -34,50 +34,8 @@ def test_02():
3434
print(w)
3535
assert w == u32(11)
3636

37-
# Disable following tests
38-
# Negative numbers in unsigned should throw errors
39-
# TODO: Add these tests as error reference tests
40-
41-
# def test_03():
42-
# x : u32 = u32(-10)
43-
# print(x)
44-
# assert x == u32(4294967286)
45-
46-
# y: u16 = u16(x)
47-
# print(y)
48-
# assert y == u16(65526)
49-
50-
# z: u64 = u64(y)
51-
# print(z)
52-
# assert z == u64(65526)
53-
54-
# w: u8 = u8(z)
55-
# print(w)
56-
# assert w == u8(246)
57-
58-
# def test_04():
59-
# x : u64 = u64(-11)
60-
# print(x)
61-
# # TODO: We are unable to store the following u64 in AST/R
62-
# # assert x == u64(18446744073709551605)
63-
64-
# y: u8 = u8(x)
65-
# print(y)
66-
# assert y == u8(245)
67-
68-
# z: u16 = u16(y)
69-
# print(z)
70-
# assert z == u16(245)
71-
72-
# w: u32 = u32(z)
73-
# print(w)
74-
# assert w == u32(245)
75-
76-
7737
def main0():
7838
test_01()
7939
test_02()
80-
# test_03()
81-
# test_04()
8240

8341
main0()
Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
1-
from lpython import u16, u32, u64
1+
from lpython import u8, u16, u32, u64
22

33
def f():
44

5+
h: u8
6+
h = u8(67)
7+
print(+h)
8+
assert +h == u8(67)
9+
510
i: u16
611
i = u16(67)
7-
print(-i, +i, -(-i))
8-
assert -i == u16(65469)
12+
print(+i)
913
assert +i == u16(67)
10-
assert -(-i) == u16(67)
1114

1215
j: u32
1316
j = u32(25)
14-
print(-j, +j, -(-j))
15-
assert -j == u32(4294967271)
17+
print(+j)
1618
assert +j == u32(25)
17-
assert -(-j) == u32(25)
1819

1920
k: u64
2021
k = u64(100000000000123)
21-
print(-k, +k, -(-k))
22-
# TODO: We are unable to store the following u64 in AST/R
23-
# assert -k == u64(18446644073709551493)
22+
print(+k)
2423
assert +k == u64(100000000000123)
25-
assert -(-k) == u64(100000000000123)
24+
25+
assert -u8(0) == u8(0)
26+
assert -u16(0) == u16(0)
27+
assert -u32(0) == u32(0)
28+
assert -u64(0) == u64(0)
2629

2730
f()

integration_tests/test_unsigned_01.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ def f():
44

55
h: u8
66
h = u8(5)
7-
print(h << u8(4), h << u8(7), h >> u8(4), h >> u8(7))
7+
print(h << u8(4), h << u8(2), h >> u8(4), h >> u8(7))
88
assert h << u8(4) == u8(80)
9-
assert h << u8(7) == u8(128)
9+
assert h << u8(2) == u8(20)
1010
assert h >> u8(4) == u8(0)
1111
assert h >> u8(7) == u8(0)
1212

src/libasr/asr_utils.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,14 @@ ASR::asr_t* make_Cast_t_value(Allocator &al, const Location &a_loc,
12651265
int64_t int_value = ASR::down_cast<ASR::IntegerConstant_t>(
12661266
ASRUtils::expr_value(a_arg))->m_n;
12671267
value = ASR::down_cast<ASR::expr_t>(ASR::make_UnsignedIntegerConstant_t(al, a_loc, int_value, a_type));
1268+
} else if (a_kind == ASR::cast_kindType::UnsignedIntegerToInteger) {
1269+
int64_t int_value = ASR::down_cast<ASR::UnsignedIntegerConstant_t>(
1270+
ASRUtils::expr_value(a_arg))->m_n;
1271+
value = ASR::down_cast<ASR::expr_t>(ASR::make_IntegerConstant_t(al, a_loc, int_value, a_type));
1272+
} else if (a_kind == ASR::cast_kindType::UnsignedIntegerToUnsignedInteger) {
1273+
int64_t int_value = ASR::down_cast<ASR::UnsignedIntegerConstant_t>(
1274+
ASRUtils::expr_value(a_arg))->m_n;
1275+
value = ASR::down_cast<ASR::expr_t>(ASR::make_UnsignedIntegerConstant_t(al, a_loc, int_value, a_type));
12681276
} else if (a_kind == ASR::cast_kindType::IntegerToLogical) {
12691277
// TODO: implement
12701278
} else if (a_kind == ASR::cast_kindType::ComplexToComplex) {

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3646,8 +3646,20 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
36463646
if (ASRUtils::expr_value(operand) != nullptr) {
36473647
int64_t op_value = ASR::down_cast<ASR::UnsignedIntegerConstant_t>(
36483648
ASRUtils::expr_value(operand))->m_n;
3649+
if (op_value != 0) {
3650+
int kind = ASRUtils::extract_kind_from_ttype_t(operand_type);
3651+
int signed_promote_kind = (kind < 8) ? kind * 2 : kind;
3652+
diag.add(diag::Diagnostic(
3653+
"The result of the unary minus `-` operation is negative, thus out of range for u" + std::to_string(kind * 8),
3654+
diag::Level::Error, diag::Stage::Semantic, {
3655+
diag::Label("use -i" + std::to_string(signed_promote_kind * 8)
3656+
+ "(u) for signed result", {x.base.base.loc})
3657+
})
3658+
);
3659+
throw SemanticAbort();
3660+
}
36493661
value = ASR::down_cast<ASR::expr_t>(ASR::make_UnsignedIntegerConstant_t(
3650-
al, x.base.base.loc, -op_value, operand_type));
3662+
al, x.base.base.loc, 0, operand_type));
36513663
}
36523664
tmp = ASR::make_UnsignedIntegerUnaryMinus_t(al, x.base.base.loc, operand,
36533665
operand_type, value);
@@ -7615,6 +7627,15 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
76157627
target_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, x.base.base.loc));
76167628
}
76177629
ASR::expr_t* arg = args[0].m_value;
7630+
if (ASR::is_a<ASR::UnsignedInteger_t>(*target_type)) {
7631+
int64_t value_int;
7632+
if( ASRUtils::extract_value(ASRUtils::expr_value(arg), value_int) ) {
7633+
if (value_int < 0) {
7634+
throw SemanticError("Cannot cast negative value to unsigned integer ",
7635+
x.base.base.loc);
7636+
}
7637+
}
7638+
}
76187639
cast_helper(target_type, arg, x.base.base.loc, true);
76197640
tmp = (ASR::asr_t*) arg;
76207641
return ;

tests/errors/unsigned_01.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from lpython import u16
2+
3+
i: u16 = u16(-5)

tests/errors/unsigned_02.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from lpython import u16
2+
3+
i: u16 = -u16(5)

tests/errors/unsigned_03.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from lpython import u32, u64
2+
3+
print(-u64(u32(10)))

tests/errors/unsigned_04.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from lpython import u16
2+
3+
i: u16 = u16(5)
4+
i = ~i

0 commit comments

Comments
 (0)