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()

integration_tests/test_unary_op_05.py

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
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "asr-unsigned_01-892b178",
3+
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
4+
"infile": "tests/errors/unsigned_01.py",
5+
"infile_hash": "c176f4ec65c0b5ca7c2c95b2e35d65f22b4cef342baad15c2dd5ef24",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": null,
9+
"stdout_hash": null,
10+
"stderr": "asr-unsigned_01-892b178.stderr",
11+
"stderr_hash": "54c7cfbd16c73cbe802a3492cd9c9e8d2fb25035192d229232c377b2",
12+
"returncode": 2
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
semantic error: Cannot cast negative value to unsigned integer
2+
--> tests/errors/unsigned_01.py:3:10
3+
|
4+
3 | i: u16 = u16(-5)
5+
| ^^^^^^^
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "asr-unsigned_02-6563e58",
3+
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
4+
"infile": "tests/errors/unsigned_02.py",
5+
"infile_hash": "7892abcbe7cecdbddc7362fd0940986bf64458880ccd198c16dd2a6e",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": null,
9+
"stdout_hash": null,
10+
"stderr": "asr-unsigned_02-6563e58.stderr",
11+
"stderr_hash": "93f2cf309dfa7f13d56df9184615fde6a832b79510d8541f95ad5a70",
12+
"returncode": 2
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
semantic error: The result of the unary minus `-` operation is negative, thus out of range for u16
2+
--> tests/errors/unsigned_02.py:3:10
3+
|
4+
3 | i: u16 = -u16(5)
5+
| ^^^^^^^ use -i32(u) for signed result
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "asr-unsigned_03-f785652",
3+
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
4+
"infile": "tests/errors/unsigned_03.py",
5+
"infile_hash": "72dd2c6e17b137b6b9f66deeaab0af4ebe3044cb16009e0fab25f05a",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": null,
9+
"stdout_hash": null,
10+
"stderr": "asr-unsigned_03-f785652.stderr",
11+
"stderr_hash": "d90013a25d9aaa91fbbf2b1193cd06be94a4e716f0fe99771cde5601",
12+
"returncode": 2
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
semantic error: The result of the unary minus `-` operation is negative, thus out of range for u64
2+
--> tests/errors/unsigned_03.py:3:7
3+
|
4+
3 | print(-u64(u32(10)))
5+
| ^^^^^^^^^^^^^ use -i64(u) for signed result
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "asr-unsigned_04-c856d3a",
3+
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
4+
"infile": "tests/errors/unsigned_04.py",
5+
"infile_hash": "d1c2f82e9578ce3f2364f4bbd3177bc0ae72357c644953418eaffe4c",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": null,
9+
"stdout_hash": null,
10+
"stderr": "asr-unsigned_04-c856d3a.stderr",
11+
"stderr_hash": "3dcdf2e97f8c5f2816bed266587c7c3743f666cf2a4602f65e8ec9b8",
12+
"returncode": 2
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
semantic error: The result of the bitnot ~ operation is negative, thus out of range for u16
2+
--> tests/errors/unsigned_04.py:4:5
3+
|
4+
4 | i = ~i
5+
| ^^ use ~i32(u) for signed result or bitnot_u16(u) for unsigned result

tests/tests.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,22 @@ asr = true
11941194
filename = "errors/func_08.py"
11951195
asr = true
11961196

1197+
[[test]]
1198+
filename = "errors/unsigned_01.py"
1199+
asr = true
1200+
1201+
[[test]]
1202+
filename = "errors/unsigned_02.py"
1203+
asr = true
1204+
1205+
[[test]]
1206+
filename = "errors/unsigned_03.py"
1207+
asr = true
1208+
1209+
[[test]]
1210+
filename = "errors/unsigned_04.py"
1211+
asr = true
1212+
11971213
# tests/runtime_errors
11981214
[[test]]
11991215
filename = "runtime_errors/test_list_01.py"

0 commit comments

Comments
 (0)