Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error message for mismatch in worker send-receive pairing #41999

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ public enum DiagnosticErrorCode implements DiagnosticCode {
WORKER_SEND_RECEIVE_PARAMETER_COUNT_MISMATCH("BCE2082", "worker.send.receive.parameter.count.mismatch"),
INVALID_WORKER_INTERACTION("BCE2083", "worker.invalid.worker.interaction"),
WORKER_INTERACTIONS_ONLY_ALLOWED_BETWEEN_PEERS("BCE2084", "worker.interactions.only.allowed.between.peers"),
STREAM_RECEIVE_ACTION_NOT_YET_SUPPORTED("BCE2085", "stream.receive.action.not.yet.supported"),
// VACANT_ERROR("BCE2086", ""),
INVALID_WORKER_SEND_NO_MATCHING_WORKER_RECEIVE("BCE2085", "invalid.worker.send.no.matching.worker.receive"),
INVALID_WORKER_RECEIVE_NO_MATCHING_WORKER_SEND("BCE2086", "invalid.worker.receive.no.matching.worker.send"),
EXPLICIT_WORKER_CANNOT_BE_DEFAULT("BCE2087", "explicit.worker.cannot.be.default"),
INVALID_MULTIPLE_FORK_JOIN_SEND("BCE2088", "worker.multiple.fork.join.send"),
INCOMPATIBLE_TYPE_REFERENCE("BCE2089", "incompatible.type.reference"),
Expand Down Expand Up @@ -815,7 +815,8 @@ public enum DiagnosticErrorCode implements DiagnosticCode {
"cannot.use.alternate.wait.action.within.multiple.wait.action"),
EXPRESSION_OF_FUTURE_TYPE_EXPECTED("BCE4057", "future.expression.expected"),
INSTANTIATION_ERROR("BCE4058", "instantiation.error"),
INVALID_BINDING_PATTERN_IN_ON_FAIL("BCE4059", "invalid.binding.pattern.in.on.fail")
INVALID_BINDING_PATTERN_IN_ON_FAIL("BCE4059", "invalid.binding.pattern.in.on.fail"),
STREAM_RECEIVE_ACTION_NOT_YET_SUPPORTED("BCE4060", "stream.receive.action.not.yet.supported")
;

private String diagnosticId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3667,6 +3667,13 @@ private static boolean isWorkerSyncSend(BLangNode action) {
return action.getKind() == NodeKind.WORKER_SYNC_SEND;
}

private static boolean isWorkerSendOrReceive(BLangNode action) {
return switch (action.getKind()) {
case WORKER_ASYNC_SEND, WORKER_SYNC_SEND, WORKER_RECEIVE -> true;
default -> false;
};
}

private static boolean isWaitAction(BLangNode action) {
return action.getKind() == NodeKind.WAIT_EXPR;
}
Expand Down Expand Up @@ -3900,8 +3907,23 @@ private boolean isWorkerSymbol(BSymbol symbol) {
}

private void reportInvalidWorkerInteractionDiagnostics(WorkerActionSystem workerActionSystem) {
this.dlog.error(workerActionSystem.getRootPosition(), DiagnosticErrorCode.INVALID_WORKER_INTERACTION,
workerActionSystem.toString());
boolean hasSendReceivePairingError = false;
for (WorkerActionStateMachine worker : workerActionSystem.finshedWorkers) {
for (BLangNode action : worker.actions) {
if (isWorkerSendOrReceive(action) && ((BLangWorkerSendReceiveExpr) action).getChannel() == null) {
hasSendReceivePairingError = true;
DiagnosticErrorCode errorCode = action.getKind() == NodeKind.WORKER_RECEIVE ?
DiagnosticErrorCode.INVALID_WORKER_RECEIVE_NO_MATCHING_WORKER_SEND :
DiagnosticErrorCode.INVALID_WORKER_SEND_NO_MATCHING_WORKER_RECEIVE;
dlog.error(action.pos, errorCode);
}
}
}

if (!hasSendReceivePairingError) {
this.dlog.error(workerActionSystem.getRootPosition(), DiagnosticErrorCode.INVALID_WORKER_INTERACTION,
workerActionSystem.toString());
}
}

private void validateWorkerActionParameters(BLangWorkerSendReceiveExpr send, BLangWorkerReceive receive) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,12 @@ error.invalid.wait.future.expr.mapping.constructors=\
error.invalid.wait.future.expr.actions=\
''wait'' cannot be used with actions

error.invalid.worker.send.no.matching.worker.receive=\
invalid worker send, no matching worker receive

error.invalid.worker.receive.no.matching.worker.send=\
invalid worker receive, no matching worker send

error.invalid.send.expr=\
expected an expression, but found an action

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,13 @@ public void testWaitCausingADeadlockNegative() {
String msg = "worker send/receive interactions are invalid; worker(s) cannot move onwards from the state: '%s'";
BAssertUtil.validateError(result, index++, String.format(msg, "[wait v, wait w, FINISHED]"), 19, 14);
BAssertUtil.validateError(result, index++, String.format(msg, "[wait v, wait w, wait x, FINISHED]"), 29, 14);
BAssertUtil.validateError(result, index++, String.format(msg, "[wait w2, <- w, wait w1, FINISHED]"), 43, 14);
BAssertUtil.validateError(result, index++, "invalid worker send, no matching worker receive", 46, 9);
BAssertUtil.validateError(result, index++, "invalid worker receive, no matching worker send", 50, 17);
BAssertUtil.validateError(result, index++, String.format(msg, "[wait v, wait w, wait x, FINISHED]"), 61, 18);
BAssertUtil.validateError(result, index++,
String.format(msg, "[wait vi, wait wi, wait xi, FINISHED, FINISHED]"), 78, 23);
BAssertUtil.validateError(result, index++,
String.format(msg, "[11 -> w3, FINISHED, FINISHED, wait {w1,w2,w3}]"), 94, 15);
BAssertUtil.validateError(result, index++, "invalid worker send, no matching worker receive", 95, 9);
BAssertUtil.validateError(result, index++, "invalid worker receive, no matching worker send", 96, 20);
Assert.assertEquals(result.getErrorCount(), index);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,29 @@
public class WorkerFailTest {

@Test
public void invalidWorkerSendReceive() {
public void testMismatchInSendReceivePairing() {
CompileResult result = BCompileUtil.compile("test-src/workers/invalid-worker-send-receive.bal");
String message = Arrays.toString(result.getDiagnostics());
Assert.assertEquals(result.getErrorCount(), 1);
Assert.assertTrue(message.contains(" interactions are invalid"), message);
String invalidSendErrMsg = "invalid worker send, no matching worker receive";
String invalidReceiveErrMsg = "invalid worker receive, no matching worker send";
int index = 0;
validateError(result, index++, invalidSendErrMsg, 3, 9);
validateError(result, index++, invalidSendErrMsg, 7, 9);
validateError(result, index++, invalidReceiveErrMsg, 13, 17);
validateError(result, index++, invalidReceiveErrMsg, 17, 20);
validateError(result, index++, invalidSendErrMsg, 29, 9);
validateError(result, index++, invalidReceiveErrMsg, 44, 21);
validateError(result, index++, invalidReceiveErrMsg, 54, 34);
validateError(result, index++, invalidReceiveErrMsg, 67, 20);
validateError(result, index++, invalidReceiveErrMsg, 67, 27);
validateError(result, index++, invalidReceiveErrMsg, 67, 34);
validateError(result, index++, invalidSendErrMsg, 71, 9);
validateWarning(result, index++, "unused variable 'b'", 79, 13);
validateError(result, index++, invalidReceiveErrMsg, 81, 17);
validateWarning(result, index++, "unused variable 'b'", 85, 13);
validateWarning(result, index++, "unused variable 'a'", 90, 13);
validateWarning(result, index++, "unused variable 'b'", 91, 13);
Assert.assertEquals(result.getErrorCount(), index - 4);
Assert.assertEquals(result.getWarnCount(), 4);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,95 @@
function case1() {
worker w1 {
20 -> w2;
}

worker w2 {
"xxx" -> w1;
}
}

function case2() {
worker w1 {
int _ = <- w2;
}

worker w2 {
string _ = <- w1;
}
}

function case3() {
boolean foo = true;
worker w1 {
if foo {
2 -> w2;
} else {
3 -> w2;
}
4 -> w2;
}

worker w2 returns error? {
_ = check <- w1;
_ = check <- w1;
}
}

function case4() {
worker w1 {
"xxx" -> w2;
}

worker w2 {
_ = <- w1 | w1;
}
}

function case5() {
worker w1 {
"xxx" -> w2;
}

worker w2 {
_ = <- {a: w1, b: w3, c: w3};
}

worker w3 {
"yyy" -> w2;
}
}

function invalidWorkerSendReceive() {
function case6() {
worker w1 {
}

worker w2 {
_ = <- {a: w1, b: w3, c: w3};
}

worker w3 {
"yyy" -> w2;
}
}

function case7() {
fork {
worker w1 {
int a = 5;
int b = 0;
a -> w2;
b = <- w3;
}
worker w2 {
int a = 0;
int b = 15;
a = <- w1;
a -> w3;
}
worker w3 {
int a = 0;
int b = 15;
a = <- w2;
}
}
}
worker w1 {
int a = 5;
int b = 0;
a -> w2;
b = <- w3;
}
worker w2 {
int a = 0;
int b = 15;
a = <- w1;
a -> w3;
}
worker w3 {
int a = 0;
int b = 15;
a = <- w2;
}
}
}
Loading