Skip to content

Commit

Permalink
Merge pull request #40023 from ushirask/issue_39959
Browse files Browse the repository at this point in the history
Fix member access with valid union type expression
  • Loading branch information
lochana-chathura authored Aug 15, 2023
2 parents c9c65ef + 21c0b39 commit 72f7e01
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8674,24 +8674,25 @@ private BType checkArrayIndexBasedAccess(BLangIndexBasedAccess indexBasedAccess,
actualType = arrayType.eType;
break;
case TypeTags.UNION:
// address the case where we have a union of finite types
List<BFiniteType> finiteTypes = ((BUnionType) indexExprType).getMemberTypes().stream()
.filter(memType -> Types.getReferredType(memType).tag == TypeTags.FINITE)
.map(matchedType -> (BFiniteType) Types.getReferredType(matchedType))
.collect(Collectors.toList());

BFiniteType finiteType;
if (finiteTypes.size() == 1) {
finiteType = finiteTypes.get(0);
} else {
Set<BLangExpression> valueSpace = new LinkedHashSet<>();
finiteTypes.forEach(constituent -> valueSpace.addAll(constituent.getValueSpace()));
finiteType = new BFiniteType(null, valueSpace);
// address the case where we have a union of types
List<BFiniteType> finiteTypes = new ArrayList<>();
for (BType memType : ((BUnionType) indexExprType).getMemberTypes()) {
memType = Types.getReferredType(memType);
if (memType.tag == TypeTags.FINITE) {
finiteTypes.add((BFiniteType) memType);
} else {
BType possibleType = checkArrayIndexBasedAccess(indexBasedAccess, memType, arrayType);
if (possibleType == symTable.semanticError) {
return symTable.semanticError;
}
}
}

BType elementType = checkArrayIndexBasedAccess(indexBasedAccess, finiteType, arrayType);
if (elementType == symTable.semanticError) {
return symTable.semanticError;
if (!finiteTypes.isEmpty()) {
BFiniteType finiteType = createFiniteTypeFromFiniteTypeList(finiteTypes);
BType possibleType = checkArrayIndexBasedAccess(indexBasedAccess, finiteType, arrayType);
if (possibleType == symTable.semanticError) {
return symTable.semanticError;
}
}
actualType = arrayType.eType;
break;
Expand Down Expand Up @@ -8782,23 +8783,15 @@ private BType checkTupleIndexBasedAccess(BLangIndexBasedAccess accessExpr, BTupl
}
}
});

BFiniteType finiteType;
if (finiteTypes.size() == 1) {
finiteType = finiteTypes.get(0);
} else {
Set<BLangExpression> valueSpace = new LinkedHashSet<>();
finiteTypes.forEach(constituent -> valueSpace.addAll(constituent.getValueSpace()));
finiteType = new BFiniteType(null, valueSpace);
}

BType possibleType = checkTupleIndexBasedAccess(accessExpr, tuple, finiteType);
if (possibleType.tag == TypeTags.UNION) {
possibleTypesByMember.addAll(((BUnionType) possibleType).getMemberTypes());
} else {
possibleTypesByMember.add(possibleType);
if (!finiteTypes.isEmpty()) {
BFiniteType finiteType = createFiniteTypeFromFiniteTypeList(finiteTypes);
BType possibleType = checkTupleIndexBasedAccess(accessExpr, tuple, finiteType);
if (possibleType.tag == TypeTags.UNION) {
possibleTypesByMember.addAll(((BUnionType) possibleType).getMemberTypes());
} else {
possibleTypesByMember.add(possibleType);
}
}

if (possibleTypesByMember.contains(symTable.semanticError)) {
return symTable.semanticError;
}
Expand Down Expand Up @@ -8969,23 +8962,15 @@ private BType checkRecordIndexBasedAccess(BLangIndexBasedAccess accessExpr, BRec
}
}
});

BFiniteType finiteType;
if (finiteTypes.size() == 1) {
finiteType = finiteTypes.get(0);
} else {
Set<BLangExpression> valueSpace = new LinkedHashSet<>();
finiteTypes.forEach(constituent -> valueSpace.addAll(constituent.getValueSpace()));
finiteType = new BFiniteType(null, valueSpace);
}

BType possibleType = checkRecordIndexBasedAccess(accessExpr, record, finiteType, data);
if (possibleType.tag == TypeTags.UNION) {
possibleTypesByMember.addAll(((BUnionType) possibleType).getMemberTypes());
} else {
possibleTypesByMember.add(possibleType);
if (!finiteTypes.isEmpty()) {
BFiniteType finiteType = createFiniteTypeFromFiniteTypeList(finiteTypes);
BType possibleType = checkRecordIndexBasedAccess(accessExpr, record, finiteType, data);
if (possibleType.tag == TypeTags.UNION) {
possibleTypesByMember.addAll(((BUnionType) possibleType).getMemberTypes());
} else {
possibleTypesByMember.add(possibleType);
}
}

if (possibleTypesByMember.contains(symTable.semanticError)) {
return symTable.semanticError;
}
Expand Down Expand Up @@ -9509,6 +9494,16 @@ private LinkedHashSet<BType> getTypeWithoutNilForNonAnyTypeWithNil(BType type) {
return memberTypes;
}

private BFiniteType createFiniteTypeFromFiniteTypeList(List<BFiniteType> finiteTypes) {
if (finiteTypes.size() == 1) {
return finiteTypes.get(0);
} else {
Set<BLangExpression> valueSpace = new LinkedHashSet<>();
finiteTypes.forEach(constituent -> valueSpace.addAll(constituent.getValueSpace()));
return new BFiniteType(null, valueSpace);
}
}

private static class FieldInfo {
List<BType> types;
boolean required;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,18 @@ public void testNegativeCases() {
374, 16);
validateError(negativeResult, i++, "incompatible types: expected 'boolean', found 'int'",
377, 17);
validateError(negativeResult, i++, "incompatible types: expected 'string', found '(string|int)'",
388, 7);
validateError(negativeResult, i++, "incompatible types: expected 'int', found '(int|float)'",
392, 9);
validateError(negativeResult, i++, "incompatible types: expected 'int', found '(string|int)'",
396, 9);
validateError(negativeResult, i++, "incompatible types: expected 'int', found 'StrOrInt1'",
399, 9);
validateError(negativeResult, i++, "incompatible types: expected 'int', found '(string|int)'",
403, 7);
validateError(negativeResult, i++, "incompatible types: expected 'int', found '(int|Str)'",
406, 7);
Assert.assertEquals(negativeResult.getErrorCount(), i);
}

Expand Down Expand Up @@ -531,6 +543,11 @@ public void testNestedMemberAccessOnIntersectionTypes() {
BRunUtil.invoke(result, "testNestedMemberAccessOnIntersectionTypes");
}

@Test
public void testMemberAccessWithUnionTypedIndexExpr() {
BRunUtil.invoke(result, "testMemberAccessWithUnionTypedIndexExpr");
}

@AfterClass
public void tearDown() {
result = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,87 @@ function testUnspecifiedFieldRecordMemberAccessWithStringCharKeyExpr() {
assertTrue(v is ());
}

type IntType1 int;
type IntType2 int|int:Signed16;
type StrType1 string|string:Char;
type IntType3 1|2|3|4;

function testMemberAccessWithUnionTypedIndexExpr() {
record {|
int a;
|} r = {a: 1};
string|string s = "a";
r[s] = 2;
assertEquality(2, r.a);

int[] arr = [1, 2, 3];
int|int|int x = 1;
arr[x] = 4;
assertEquality(4, arr[1]);

[string, int] t = ["a", 1];
int|int y = 0;
t[y] = "b";
assertEquality("b", t[0]);

record {|
int a;
|} r1 = {a: 1};
string|string:Char s1 = "a";
r1[s1] = 2;
assertEquality(2, r1.a);

string[] arr1 = ["a", "b", "c"];
int|int:Signed32 x1 = 1;
arr1[x1] = "d";
assertEquality("d", arr1[1]);

[string, int] t1 = ["a", 1];
int|IntType1|int y1 = 0;
t1[y1] = "b";
assertEquality("b", t1[0]);

[string, int, int] t2 = ["abc", 0, 1];
int:Signed16|int y2 = 0;
t2[y2] = "b";
assertEquality("b", t2[0]);

record {|
string a;
int b;
|} r2 = {a: "a", b: 1};
string|StrType1 s2 = "b";
r2[s2] = 2;
assertEquality(2, r2.b);

float[] arr2 = [0.1, 1.2, 2.3];
IntType2|int:Signed8 x2 = 0;
arr2[x2] = 4.5;
assertEquality(4.5, arr2[0]);

int[] arr3 = [1, 2, 3];
int|IntType3 x3 = 1;
arr3[x3] = 4;
assertEquality(4, arr3[1]);

record {|
int a;
|} r3 = {a: 1};
"a"|"b" s3 = "a";
r3[s3] = 2;
assertEquality(2, r3.a);

[int, string] tup = [1, "x"];
0|1|int a = 0;
tup[a] = 4;
assertEquality(4, tup[0]);

[int, string] tup2 = [1, "x"];
0|1|2 a2 = 1;
tup2[a2] = "y";
assertEquality("y", tup2[1]);
}

const ASSERTION_ERROR_REASON = "AssertionError";

function assertTrue(any|error actual) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,32 @@ function testCustomTupleTypesAccessNegative() {
var x14 = t7[2][index];
boolean _ = x14; //error: incompatible types: expected 'boolean', found 'int'
}

type Str string;
type StrOrInt1 string|int;

function testMemberAccessWithUnionTypedIndexExprNegative() {
record {|
int a;
|} r = {a: 1};
string|int s = "a";
r[s] = 2; // error: incompatible types: expected 'string', found '(string|int)'

int[] arr = [1, 2, 3];
int|float|int x = 1;
arr[x] = 4; // error: incompatible types: expected 'int', found '(int|float|int)'

string[] arr1 = ["1", "2", "3"];
string|int x2 = 1;
arr[x2] = 4; // error: incompatible types: expected 'int', found '(string|int)'

StrOrInt1 x3 = 2;
arr[x3] = "4"; // error: incompatible types: expected 'int', found 'StrOrInt1'

[string, int] t = ["a", 1];
string|int y = 0;
t[y] = "b"; // error: incompatible types: expected 'int', found '(string|int)'

int|Str y2 = 1;
t[y2] = 0; // error: incompatible types: expected 'int', found '(int|Str)'
}

0 comments on commit 72f7e01

Please sign in to comment.