Skip to content

Commit

Permalink
Merge pull request #37832 from SasinduDilshara/issue-#34821
Browse files Browse the repository at this point in the history
[Master] Fix compiler crashes when a union is used within multiple wait
  • Loading branch information
pcnfernando authored Aug 15, 2023
2 parents cebd881 + 511c87c commit c9c65ef
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -805,11 +805,13 @@ public enum DiagnosticErrorCode implements DiagnosticCode {
SEQUENCE_VARIABLE_CAN_BE_USED_IN_SINGLE_ELEMENT_LIST_CTR_OR_FUNC_INVOCATION(
"BCE4047", "seq.var.used.in.single.element.list.ctr.or.func.invocation"),
SEQ_ARG_FOLLOWED_BY_ANOTHER_SEQ_ARG("BCE4048", "seq.arg.followed.by.another.seq.arg"),

QUERY_CONSTRUCT_TYPES_CANNOT_BE_USED_WITH_COLLECT("BCE4049", "query.construct.types.cannot.be.used.with.collect"),
VARIABLE_IS_SEQUENCED_MORE_THAN_ONCE("BCE4050", "variable.is.sequenced.more.than.once"),
INVALID_GROUPING_KEY_TYPE("BCE4051", "invalid.grouping.key.type"),
NAMED_ARG_NOT_ALLOWED_FOR_REST_PARAM("BCE4052", "named.arg.not.allowed.for.rest.param")
NAMED_ARG_NOT_ALLOWED_FOR_REST_PARAM("BCE4052", "named.arg.not.allowed.for.rest.param"),
CANNOT_USE_ALTERNATE_WAIT_ACTION_WITHIN_MULTIPLE_WAIT_ACTION("BCE4053",
"cannot.use.alternate.wait.action.within.multiple.wait.action"),
EXPRESSION_OF_FUTURE_TYPE_EXPECTED("BCE4054", "future.expression.expected")
;

private String diagnosticId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4721,7 +4721,12 @@ private void checkTypesForRecords(BLangWaitForAllExpr waitExpr, AnalyzerData dat

for (BLangWaitForAllExpr.BLangWaitKeyValue keyVal : rhsFields) {
String key = keyVal.key.value;
if (!lhsFields.containsKey(key)) {
BLangExpression valueExpr = keyVal.valueExpr;
if (valueExpr != null && isBinaryBitwiseOperatorExpr(valueExpr)) {
dlog.error(valueExpr.pos,
DiagnosticErrorCode.CANNOT_USE_ALTERNATE_WAIT_ACTION_WITHIN_MULTIPLE_WAIT_ACTION);
data.resultType = symTable.semanticError;
} else if (!lhsFields.containsKey(key)) {
// Check if the field is sealed if so you cannot have dynamic fields
if (((BRecordType) Types.getReferredType(data.expType)).sealed) {
dlog.error(waitExpr.pos, DiagnosticErrorCode.INVALID_FIELD_NAME_RECORD_LITERAL, key, data.expType);
Expand All @@ -4746,6 +4751,17 @@ private void checkTypesForRecords(BLangWaitForAllExpr waitExpr, AnalyzerData dat
}
}

private boolean isBinaryBitwiseOperatorExpr(BLangExpression valueExpr) {
if (valueExpr.getKind() == NodeKind.GROUP_EXPR) {
return isBinaryBitwiseOperatorExpr(((BLangGroupExpr) valueExpr).expression);
}
if (valueExpr.getKind() == NodeKind.BINARY_EXPR
&& ((BLangBinaryExpr) valueExpr).opKind == OperatorKind.BITWISE_OR) {
return true;
}
return false;
}

private void checkMissingReqFieldsForWait(BRecordType type, List<BLangWaitForAllExpr.BLangWaitKeyValue> keyValPairs,
Location pos) {
type.fields.values().forEach(field -> {
Expand Down Expand Up @@ -4783,7 +4799,14 @@ private void setEventualTypeForExpression(BLangExpression expression,
if (isSimpleWorkerReference(expression, data)) {
return;
}
BFutureType futureType = (BFutureType) expression.expectedType;

BType expectedType = expression.expectedType;
if (expectedType.tag != TypeTags.FUTURE) {
dlog.error(expression.pos, DiagnosticErrorCode.EXPRESSION_OF_FUTURE_TYPE_EXPECTED, expectedType);
return;
}

BFutureType futureType = (BFutureType) expectedType;
BType currentType = futureType.constraint;
if (types.containsErrorType(currentType)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1971,6 +1971,12 @@ error.empty.regexp.string.disallowed=\
error.unsupported.empty.character.class=\
empty character class disallowed

error.cannot.use.alternate.wait.action.within.multiple.wait.action=\
cannot use an alternate wait action within a multiple wait action

error.future.expression.expected=\
expected an expression of type ''future'', found ''{0}''

error.cyclic.type.reference.not.yet.supported=\
cyclic type reference not yet supported for ''{0}''

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public class WaitActionsNegativeTest {
public void testNegativeWorkerActions() {
CompileResult resultNegative = BCompileUtil.compile("test-src/workers/wait-actions-negative.bal");
int index = 0;
Assert.assertEquals(resultNegative.getErrorCount(), 45, "Wait actions negative test error count");
BAssertUtil.validateError(resultNegative, index++,
"incompatible types: expected 'future<string>', found 'future<int>'", 56, 22);
BAssertUtil.validateError(resultNegative, index++,
Expand Down Expand Up @@ -143,9 +142,34 @@ public void testNegativeWorkerActions() {
"expression 'f2'", 90, 45);
BAssertUtil.validateError(resultNegative, index++,
"incompatible types: expected 'future<string>', found 'future<(int|error)>'", 90, 54);
BAssertUtil.validateError(resultNegative, index,
BAssertUtil.validateError(resultNegative, index++,
"incompatible types: expected 'string', found eventual type '(string|error)' for wait future " +
"expression 'f4'", 90, 54);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 115, 38);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 116, 48);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 117, 27);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 117, 58);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 119, 27);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 120, 48);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 121, 27);
BAssertUtil.validateError(resultNegative, index++,
"cannot use an alternate wait action within a multiple wait action", 121, 72);
BAssertUtil.validateError(resultNegative, index++, "expected an expression of type 'future'," +
" found '(future<(boolean|error)>|future<(boolean|error)>)'", 136, 38);
BAssertUtil.validateError(resultNegative, index++, "expected an expression of type 'future'," +
" found '(future<boolean>|future<boolean>)'", 137, 48);
BAssertUtil.validateError(resultNegative, index++, "expected an expression of type 'future'," +
" found '(future<(boolean|error)>|future<(boolean|error)>)'", 138, 27);
BAssertUtil.validateError(resultNegative, index++, "expected an expression of type 'future'," +
" found '(future<boolean>|future<boolean>)'", 138, 40);
Assert.assertEquals(resultNegative.getErrorCount(), index, "Wait actions negative test error count");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,54 @@ function waitForAllTest() {
restRec2 result16 = wait {id: f1, name: f2, age: f4};
}

type WaitResult record {|
boolean|error producer;
boolean consumer;
|};

function waitForAllTest2() {
worker Producer1 returns boolean|error {
return true;
}

worker Producer2 returns boolean|error {
return true;
}

worker Consumer1 returns boolean {
return false;
}

worker Consumer2 returns boolean {
return false;
}

WaitResult res = wait {producer: Producer1|Producer2, consumer: Consumer1};
res = wait {producer: Producer1, consumer: Consumer1|Consumer2};
res = wait {producer: Producer1|Producer2, consumer: Consumer1|Consumer2};

res = wait {producer: (Producer1|(Producer2)), consumer: Consumer1};
res = wait {producer: Producer1, consumer: (((Consumer1|Consumer2)))};
res = wait {producer: (((((((Producer1|Producer2))))))), consumer: (Consumer1|Consumer2)};
}

function waitActionWithInvalidType() {
worker Producer1 returns boolean|error {
return true;
}

worker Consumer1 returns boolean {
return false;
}

future<boolean|error>|future<boolean|error> x = Producer1;
future<boolean>|future<boolean> y = Consumer1;

WaitResult res = wait {producer: x, consumer: Consumer1};
res = wait {producer: Producer1, consumer: y};
res = wait {producer: x, consumer: y};
}

function print(string str) {
string result = str.toUpperAscii();
}
Expand Down

0 comments on commit c9c65ef

Please sign in to comment.