Skip to content

Commit e445448

Browse files
committed
dslx: allow non-trivial final expressions in proc's config
1 parent 9294da4 commit e445448

File tree

3 files changed

+149
-13
lines changed

3 files changed

+149
-13
lines changed

xls/dslx/frontend/parser.cc

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3120,16 +3120,6 @@ absl::StatusOr<Function*> Parser::ParseProcConfig(
31203120
// Implicitly nil tuple as a result.
31213121
} else {
31223122
Expr* final_expr = std::get<Expr*>(block->statements().back()->wrapped());
3123-
3124-
if (dynamic_cast<XlsTuple*>(final_expr) == nullptr) {
3125-
Span final_stmt_span =
3126-
ToAstNode(block->statements().back()->wrapped())->GetSpan().value();
3127-
return ParseErrorStatus(
3128-
final_stmt_span,
3129-
"The final expression in a Proc config must be a tuple with one "
3130-
"element for each Proc data member.");
3131-
}
3132-
31333123
VLOG(5) << "ParseProcConfig; final expr: `" << final_expr->ToString()
31343124
<< "`";
31353125
}

xls/dslx/type_system/proc_typecheck_test.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,7 @@ proc entry {
119119
EXPECT_THAT(TypecheckV2(kProgram),
120120
absl_testing::StatusIs(
121121
absl::StatusCode::kInvalidArgument,
122-
testing::HasSubstr(
123-
"final expression in a Proc config must be a tuple with "
124-
"one element for each Proc data member")));
122+
HasTypeMismatch("(chan<u32> in,)", "u32")));
125123
}
126124

127125
TEST(TypecheckTest, RecvIfDefaultValueWrongType) {

xls/dslx/type_system_v2/typecheck_module_v2_test.cc

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7416,6 +7416,154 @@ proc Proc {
74167416
HasNodeWithType("b", "chan(sN[32], dir=in)[2]"))));
74177417
}
74187418

7419+
TEST(TypecheckV2Test, ProcConfigRequireTuple) {
7420+
EXPECT_THAT(
7421+
R"(
7422+
proc Proc {
7423+
input: chan<()> in;
7424+
config(input: chan<()> in) {
7425+
(input)
7426+
}
7427+
init { () }
7428+
next(state: ()) { () }
7429+
}
7430+
7431+
)",
7432+
TypecheckFails(
7433+
HasTypeMismatch("(chan<()> in,)", "chan<()> in")));
7434+
}
7435+
7436+
TEST(TypecheckV2Test, ProcConfigTooFewChannels) {
7437+
EXPECT_THAT(
7438+
R"(
7439+
proc Proc {
7440+
input: chan<()> in;
7441+
output: chan<()> out;
7442+
config(input: chan<()> in) {
7443+
(input,)
7444+
}
7445+
init { () }
7446+
next(state: ()) { () }
7447+
}
7448+
7449+
)",
7450+
TypecheckFails(
7451+
HasSubstr("Cannot match a 2-element tuple to 1 values.")));
7452+
}
7453+
7454+
TEST(TypecheckV2Test, ProcConfigTooManyChannels) {
7455+
EXPECT_THAT(
7456+
R"(
7457+
proc Proc {
7458+
req: chan<()> in;
7459+
resp: chan<()> out;
7460+
config(data_in: chan<()> in) {
7461+
let (resp, req) = chan<()>("io");
7462+
(req, resp, data_in)
7463+
}
7464+
init { () }
7465+
next(state: ()) { () }
7466+
}
7467+
7468+
)",
7469+
TypecheckFails(
7470+
HasSubstr("Out-of-bounds tuple index specified: 2")));
7471+
}
7472+
7473+
TEST(TypecheckV2Test, ProcConfigMismatchingChannelTypes) {
7474+
EXPECT_THAT(
7475+
R"(
7476+
proc Proc {
7477+
req: chan<()> in;
7478+
resp: chan<()> out;
7479+
data_in: chan<u32> in;
7480+
data_out: chan<u32> out;
7481+
config(data_in: chan<u32> in, data_out: chan<u32> out) {
7482+
let (resp, req) = chan<()>("io");
7483+
(data_in, data_out, req, resp)
7484+
}
7485+
init { () }
7486+
next(state: ()) { () }
7487+
}
7488+
7489+
)",
7490+
TypecheckFails(HasTypeMismatch("()", "u32")));
7491+
}
7492+
7493+
TEST(TypecheckV2Test, ProcWithBranchedFinalExpression) {
7494+
EXPECT_THAT(
7495+
R"(
7496+
const A = u32:5;
7497+
proc Proc {
7498+
input: chan<()> in;
7499+
output: chan<()> out;
7500+
config() {
7501+
const if A == u32:1 {
7502+
let (first_output, first_input) = chan<()>("first");
7503+
(first_input, first_output)
7504+
} else {
7505+
let (second_output, second_input) = chan<()>("second");
7506+
(second_input, second_output)
7507+
}
7508+
}
7509+
init { () }
7510+
next(state: ()) { () }
7511+
}
7512+
7513+
)",
7514+
TypecheckSucceeds(
7515+
AllOf(HasNodeWithType("second_input", "chan((), dir=in)"),
7516+
HasNodeWithType("second_output", "chan((), dir=out)"))));
7517+
}
7518+
7519+
TEST(TypecheckV2Test, ProcConfigBranchedChannelTypeMismatch) {
7520+
EXPECT_THAT(
7521+
R"(
7522+
const A = u32:4;
7523+
proc Proc {
7524+
input: chan<u32> in;
7525+
output: chan<u32> out;
7526+
config() {
7527+
const if A == u32:5 {
7528+
let (first_output, first_input) = chan<u32>("first");
7529+
(first_input, first_output)
7530+
} else {
7531+
let (second_output, second_input) = chan<()>("second");
7532+
(second_input, second_output)
7533+
}
7534+
}
7535+
init { () }
7536+
next(state: ()) { () }
7537+
}
7538+
7539+
)",
7540+
TypecheckFails(HasTypeMismatch("()", "u32")));
7541+
}
7542+
7543+
TEST(TypecheckV2Test, ProcConfigFailedBranchedFinalExpression) {
7544+
EXPECT_THAT(
7545+
R"(
7546+
const A = u32:5;
7547+
proc Proc {
7548+
input: chan<()> in;
7549+
output: chan<()> out;
7550+
config() {
7551+
const if A == u32:5 {
7552+
let (first_output, first_input) = chan<()>("first");
7553+
(first_input,)
7554+
} else {
7555+
let (second_output, second_input) = chan<()>("second");
7556+
(second_input, second_output)
7557+
}
7558+
}
7559+
init { () }
7560+
next(state: ()) { () }
7561+
}
7562+
7563+
)",
7564+
TypecheckFails(HasSubstr("Cannot match a 2-element tuple to 1 values.")));
7565+
}
7566+
74197567
TEST(TypecheckV2Test, ImportParametricFunctionWithDefaultExpression) {
74207568
constexpr std::string_view kImported = R"(
74217569
pub fn some_function<N: u32, M: u32 = {N + 1}>() -> uN[M] { uN[M]:0 }

0 commit comments

Comments
 (0)