diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java index 92ad0a013262..706d56bf2b18 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java @@ -2808,7 +2808,7 @@ private void generateMappingAccess(BLangIndexBasedAccess astIndexBasedAccessExpr if (astIndexBasedAccessExpr.getKind() == NodeKind.XML_ATTRIBUTE_ACCESS_EXPR) { insKind = InstructionKind.XML_ATTRIBUTE_LOAD; keyRegIndex = getQNameOP(astIndexBasedAccessExpr.indexExpr, keyRegIndex); - } else if (TypeTags.isXMLTypeTag(astAccessExprExprType.tag)) { + } else if (types.isAssignable(astAccessExprExprType, symTable.xmlType)) { generateXMLAccess((BLangXMLAccessExpr) astIndexBasedAccessExpr, tempVarRef, varRefRegIndex, keyRegIndex); this.varAssignment = variableStore; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java index 3e2bebf2bdf3..be62805253fd 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java @@ -754,7 +754,7 @@ private void generateFrameClassFieldLoad(List localVars, MethodV mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_BSTRING); mv.visitVarInsn(ASTORE, index); - } else if (TypeTags.isXMLTypeTag(bType.tag)) { + } else if (types.isAssignable(bType, symbolTable.xmlType)) { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_XML); mv.visitVarInsn(ASTORE, index); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java index d27017ae9bc7..5648cd152789 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java @@ -6433,7 +6433,7 @@ public void visit(BLangIndexBasedAccess indexAccessExpr) { } else if (types.isSubTypeOfList(varRefType)) { targetVarRef = new BLangArrayAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr, indexAccessExpr.indexExpr); - } else if (TypeTags.isXMLTypeTag(varRefType.tag)) { + } else if (types.isAssignable(varRefType, symTable.xmlType)) { targetVarRef = new BLangXMLAccessExpr(indexAccessExpr.pos, indexAccessExpr.expr, indexAccessExpr.indexExpr); } else if (types.isAssignable(varRefType, symTable.stringType)) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java index c4fdef5dae33..2794eea05736 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java @@ -8703,7 +8703,7 @@ private BType checkIndexAccessExpr(BLangIndexBasedAccess indexBasedAccessExpr, A indexBasedAccessExpr.originalType = symTable.charStringType; actualType = symTable.charStringType; - } else if (TypeTags.isXMLTypeTag(varRefType.tag)) { + } else if (types.isAssignable(varRefType, symTable.xmlType)) { if (indexBasedAccessExpr.isLValue) { indexExpr.setBType(symTable.semanticError); dlog.error(indexBasedAccessExpr.pos, DiagnosticErrorCode.CANNOT_UPDATE_XML_SEQUENCE); diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java index 4d45e9e88951..6b1b63b1ae96 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java @@ -259,6 +259,11 @@ public void testLengthOfXMLSequence() { Assert.assertEquals(returns.get(3), 2L); } + @Test + public void testInvalidXMLUnionAccessWithNegativeIndex() { + BRunUtil.invoke(result, "testInvalidXMLUnionAccessWithNegativeIndex"); + } + @Test public void testInvalidXMLAccessWithNegativeIndex() { BRunUtil.invoke(result, "testInvalidXMLAccessWithNegativeIndex"); @@ -269,6 +274,11 @@ public void testXmlAccessWithLargerIndex() { BRunUtil.invoke(result, "testXmlAccessWithLargerIndex"); } + @Test + public void testXmlIndexedAccessWithUnionType() { + BRunUtil.invoke(result, "testXmlIndexedAccessWithUnionType"); + } + @Test public void testXMLNavExpressionNegative() { String methodInvocMessage = "method invocations are not yet supported within XML navigation expressions, " + diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-indexed-access.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-indexed-access.bal index e45c0218b6e9..5932de9c9c63 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-indexed-access.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-indexed-access.bal @@ -444,6 +444,150 @@ function testXmlAccessWithLargerIndex() { assert(xmlValue, xml ``); } +type XmlType1 xml:Text|xml:Comment; + +type XmlType2 xml; + +type XmlType3 XmlType1|XmlType2; + +function testXmlIndexedAccessWithUnionType() { + xml value; + xml:Element|xml:Comment x1 = xml `abc`; + value = x1[0]; + assert(value, xml `abc`); + assertTrue(typeof value is typedesc); + value = x1[1]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + + xml:Element|xml:Text x2 = xml `Hello World`; + value = x2[0]; + assert(value, xml `Hello World`); + assertTrue(typeof value is typedesc); + value = x2[0][1]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + + xml:Element|xml:ProcessingInstruction x3 = xml ``; + value = x3[0]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + value = x3[1][100]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + + xml:Element|xml:Comment x4 = xml ``; + value = x4[0]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + value = x4[10]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + + xml:Text|xml:Comment x5 = xml ``; + value = x5[0]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + + xml:ProcessingInstruction|xml:Comment x6 = xml ``; + value = x6[0]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + + xml:ProcessingInstruction|xml:Text x7 = xml `Test Text`; + value = x7[0]; + assert(value, xml `Test Text`); + assertTrue(typeof value is typedesc); + + xml|xml:Comment x8 = xml `abcdef`; + value = x8[0]; + assert(value, xml `abc`); + assertTrue(typeof value is typedesc); + + xml|xml x9 = xml `ghijkl`; + value = x9[0]; + assert(value, xml `ghi`); + assertTrue(typeof value is typedesc); + + xml|xml x10 = xml `Dan Brown`; + value = x10[0]; + assert(value, xml `Dan Brown`); + assertTrue(typeof value is typedesc); + value = x10[1]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); + + XmlType1 x11 = xml `Hello!`; + value = x11[0]; + assert(value, xml `Hello!`); + assertTrue(typeof value is typedesc); + + XmlType2 x12 = xml `Sherlock HolmesDetective`; + value = x12[0]; + assert(value, xml `Sherlock Holmes`); + assertTrue(typeof value is typedesc); + value = x12[1]; + assert(value, xml `Detective`); + assertTrue(typeof value is typedesc); + + XmlType3 x13 = xml `Sherlock Holmes`; + value = x13[0]; + assert(value, xml `Sherlock Holmes`); + assertTrue(typeof value is typedesc); + value = x13[50][1]; + assert(value, xml ``); + assertTrue(typeof value is typedesc); +} + +function testInvalidXMLUnionAccessWithNegativeIndex() { + int a = -1; + xml:Element|xml:Comment x1 = xml `abc`; + string errorMessage = "xml sequence index out of range. Length: '1' requested: '-1'"; + + xml|error e = trap x1[-1]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x1[a]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x1[i]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + + xml|xml x2 = xml `Dan Brown`; + e = trap x2[-1]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x2[a]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x2[i]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + + XmlType1 x3 = xml `Hello!`; + e = trap x3[-1]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x3[a]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x3[i]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + + XmlType3 x4 = xml `Sherlock Holmes`; + e = trap x4[-1]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x4[a]; + assertTrue(e is error); + assert(( e).message(), errorMessage); + e = trap x4[i]; + assertTrue(e is error); + assert(( e).message(), errorMessage); +} + function assert(anydata actual, anydata expected) { if (expected != actual) { typedesc expT = typeof expected;