Skip to content

Commit 697061d

Browse files
cdlearycopybara-github
authored andcommitted
[DSLX:TS] Properly type check signed number concat as an error.
Fixes #1265 PiperOrigin-RevId: 599977690
1 parent ad567ac commit 697061d

File tree

3 files changed

+33
-10
lines changed

3 files changed

+33
-10
lines changed

docs_src/dslx_reference.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,8 +1260,11 @@ operations return a result of type `bits[1]`, aka `bool`.
12601260

12611261
Bitwise concatenation is performed with the `++` operator. The value on the left
12621262
hand side becomes the most significant bits, the value on the right hand side
1263-
becomes the least significant bits. These may be chained together as shown
1264-
below:
1263+
becomes the least significant bits. Both of the operands must be unsigned (see
1264+
[numerical conversions](#numerical-conversions) for details on converting signed
1265+
numbers to unsigned).
1266+
1267+
Concatenation operations may be chained together as shown:
12651268

12661269
```dslx
12671270
#[test]
@@ -1603,14 +1606,17 @@ for semantics of numeric casts:
16031606
fn test_numerical_conversions() {
16041607
let s8_m2 = s8:-2;
16051608
let u8_m2 = u8:0xfe;
1606-
// Sign extension (source type is signed).
1609+
1610+
// Sign extension (source type is signed, and we widen it).
16071611
assert_eq(s32:-2, s8_m2 as s32);
16081612
assert_eq(u32:0xfffffffe, s8_m2 as u32);
16091613
assert_eq(s16:-2, s8_m2 as s16);
16101614
assert_eq(u16:0xfffe, s8_m2 as u16);
1611-
// Zero extension (source type is unsigned).
1615+
1616+
// Zero extension (source type is unsigned, and we widen it).
16121617
assert_eq(u32:0xfe, u8_m2 as u32);
16131618
assert_eq(s32:0xfe, u8_m2 as s32);
1619+
16141620
// Nop (bitwidth is unchanged).
16151621
assert_eq(s8:-2, s8_m2 as s8);
16161622
assert_eq(s8:-2, u8_m2 as s8);

xls/dslx/type_system/deduce_expr.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,13 @@ static absl::StatusOr<std::unique_ptr<ConcreteType>> DeduceConcat(
427427
"either both-arrays or both-bits");
428428
}
429429

430+
if (lhs_bits->is_signed() || rhs_bits->is_signed()) {
431+
return ctx->TypeMismatchError(
432+
node->span(), node->lhs(), *lhs, node->rhs(), *rhs,
433+
"Concatenation requires operand types to both be "
434+
"unsigned bits");
435+
}
436+
430437
XLS_RET_CHECK(lhs_bits != nullptr);
431438
XLS_RET_CHECK(rhs_bits != nullptr);
432439
XLS_ASSIGN_OR_RETURN(ConcreteTypeDim new_size,

xls/dslx/type_system/typecheck_test.cc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,7 +2097,6 @@ fn f(x: u32) -> u32 {
20972097
)";
20982098
XLS_ASSERT_OK_AND_ASSIGN(TypecheckedModule tm, Typecheck(program));
20992099
ASSERT_THAT(tm.warnings.warnings().size(), 1);
2100-
std::string filename = "fake.x";
21012100
EXPECT_EQ(tm.warnings.warnings().at(0).message,
21022101
"Definition of `y` (type `uN[32]`) is not used in function `f`");
21032102
}
@@ -2111,7 +2110,6 @@ fn f(t: (u32, u32, u32, u32, u32)) -> u32 {
21112110
)";
21122111
XLS_ASSERT_OK_AND_ASSIGN(TypecheckedModule tm, Typecheck(program));
21132112
ASSERT_THAT(tm.warnings.warnings().size(), 5);
2114-
std::string filename = "fake.x";
21152113
EXPECT_EQ(tm.warnings.warnings().at(0).message,
21162114
"Definition of `a` (type `uN[32]`) is not used in function `f`");
21172115
EXPECT_EQ(tm.warnings.warnings().at(1).message,
@@ -2134,7 +2132,6 @@ fn f(x: u32) -> u32 {
21342132
)";
21352133
XLS_ASSERT_OK_AND_ASSIGN(TypecheckedModule tm, Typecheck(program));
21362134
ASSERT_THAT(tm.warnings.warnings().size(), 1);
2137-
std::string filename = "fake.x";
21382135
EXPECT_EQ(tm.warnings.warnings().at(0).message,
21392136
"Definition of `y` (type `uN[32]`) is not used in function `f`");
21402137
}
@@ -2143,12 +2140,25 @@ TEST(TypecheckTest, ConcatU1U1) {
21432140
XLS_ASSERT_OK(Typecheck("fn f(x: u1, y: u1) -> u2 { x ++ y }"));
21442141
}
21452142

2146-
TEST(TypecheckTest, ConcatU1S1) {
2147-
XLS_ASSERT_OK(Typecheck("fn f(x: u1, y: s1) -> u2 { x ++ y }"));
2143+
TEST(TypecheckErrorTest, ConcatU1S1) {
2144+
EXPECT_THAT(
2145+
Typecheck("fn f(x: u1, y: s1) -> u2 { x ++ y }").status(),
2146+
IsPosError("XlsTypeError", HasSubstr("Concatenation requires operand "
2147+
"types to both be unsigned bits")));
2148+
}
2149+
2150+
TEST(TypecheckErrorTest, ConcatS1S1) {
2151+
EXPECT_THAT(
2152+
Typecheck("fn f(x: s1, y: s1) -> u2 { x ++ y }").status(),
2153+
IsPosError("XlsTypeError", HasSubstr("Concatenation requires operand "
2154+
"types to both be unsigned bits")));
21482155
}
21492156

21502157
TEST(TypecheckTest, ConcatU2S1) {
2151-
XLS_ASSERT_OK(Typecheck("fn f(x: u2, y: s1) -> u3 { x ++ y }"));
2158+
EXPECT_THAT(
2159+
Typecheck("fn f(x: u2, y: s1) -> u3 { x ++ y }").status(),
2160+
IsPosError("XlsTypeError", HasSubstr("Concatenation requires operand "
2161+
"types to both be unsigned bits")));
21522162
}
21532163

21542164
TEST(TypecheckTest, ConcatU1Nil) {

0 commit comments

Comments
 (0)