diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java index 9c74dadf5972..99dc211691e2 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java @@ -25,6 +25,7 @@ import io.ballerina.types.Context; import io.ballerina.types.Core; import io.ballerina.types.Env; +import io.ballerina.types.MappingAtomicType; import io.ballerina.types.PredefinedType; import io.ballerina.types.SemType; import io.ballerina.types.SemTypes; @@ -324,41 +325,41 @@ public boolean isLaxFieldAccessAllowed(BType type) { return false; } - type = Types.getImpliedType(type); - Set visited = new HashSet<>(); - return isLaxType(type, visited) == 1 || isAssignable(type, symTable.xmlType); + return SemTypeHelper.isSubtype(semTypeCtx, type, PredefinedType.XML) || isLaxType(type); } - // TODO : clean - public int isLaxType(BType type, Set visited) { - type = getImpliedType(type); - if (!visited.add(type)) { - return -1; + private boolean isLaxType(BType type) { + SemType t = SemTypeHelper.semType(type); + return isLaxType(t); + } + + /** + * Checks if the type is a lax type. + *

+ * Rules: + *

+ * + * @param t type to be checked + * @return true if t is lax + */ + private boolean isLaxType(SemType t) { + SemType json = Core.createJson(semTypeCtx); + if (SemTypes.isSubtype(semTypeCtx, t, json) || + SemTypes.isSameType(semTypeCtx, t, SemTypes.intersect(json, PredefinedType.VAL_READONLY))) { + return true; } - switch (type.tag) { - case TypeTags.JSON: - return 1; - case TypeTags.MAP: - return isLaxType(((BMapType) type).constraint, visited); - case TypeTags.UNION: - if (isSameType(type, symTable.jsonType)) { - visited.add(type); - return 1; - } - boolean atleastOneLaxType = false; - for (BType member : ((BUnionType) type).getMemberTypes()) { - int result = isLaxType(member, visited); - if (result == -1) { - continue; - } - if (result == 0) { - return 0; - } - atleastOneLaxType = true; - } - return atleastOneLaxType ? 1 : 0; + + Optional> optMatList = Core.mappingAtomicTypesInUnion(semTypeCtx, t); + if (optMatList.isEmpty()) { + return false; } - return 0; + + List matList = optMatList.get(); + return matList.stream().allMatch(mat -> mat.names().length == 0 && isLaxType(Core.cellInnerVal(mat.rest()))); } public boolean isSameType(BType source, BType target) { diff --git a/semtypes/src/main/java/io/ballerina/types/Core.java b/semtypes/src/main/java/io/ballerina/types/Core.java index ce9fb7353a98..d9259e76b27c 100644 --- a/semtypes/src/main/java/io/ballerina/types/Core.java +++ b/semtypes/src/main/java/io/ballerina/types/Core.java @@ -22,6 +22,7 @@ import io.ballerina.types.subtypedata.AllOrNothingSubtype; import io.ballerina.types.subtypedata.BddAllOrNothing; import io.ballerina.types.subtypedata.BddNode; +import io.ballerina.types.subtypedata.BddNodeImpl; import io.ballerina.types.subtypedata.BddNodeSimple; import io.ballerina.types.subtypedata.BooleanSubtype; import io.ballerina.types.subtypedata.DecimalSubtype; @@ -770,4 +771,52 @@ public static SemType createBasicSemType(BasicTypeCode typeCode, SubtypeData sub BasicSubtype.from(typeCode, (ProperSubtypeData) subtypeData)); } } + + // ------------------------- Newly Introduced APIs (Does not exist in nBallerina) -------------------------------- + + // Consider map|map|...|map. This API will return all MappingAtomicTypes in the union. + public static Optional> mappingAtomicTypesInUnion(Context cx, SemType t) { + ArrayList matList = new ArrayList<>(); + MappingAtomicType mappingAtomicInner = MAPPING_ATOMIC_INNER; + if (t instanceof BasicTypeBitSet b) { + if (b.bitset == MAPPING.bitset) { + matList.add(mappingAtomicInner); + return Optional.of(matList); + } + return Optional.empty(); + } else { + Env env = cx.env; + if (!isSubtypeSimple(t, MAPPING)) { + return Optional.empty(); + } + return collectBddMappingAtomicTypesInUnion(env, + (Bdd) getComplexSubtypeData((ComplexSemType) t, BT_MAPPING), + mappingAtomicInner, matList) ? Optional.of(matList) : Optional.empty(); + } + } + + private static boolean collectBddMappingAtomicTypesInUnion(Env env, Bdd bdd, MappingAtomicType top, + List matList) { + if (bdd instanceof BddAllOrNothing allOrNothing) { + if (allOrNothing.isAll()) { + matList.add(top); + return true; + } + return false; + } + BddNode bddNode = (BddNode) bdd; + if (bddNode instanceof BddNodeSimple bddNodeSimple) { + matList.add(env.mappingAtomType(bddNodeSimple.atom())); + return true; + } + + BddNodeImpl bddNodeImpl = (BddNodeImpl) bddNode; + if (bddNodeImpl.left() instanceof BddAllOrNothing leftNode && leftNode.isAll() && + bddNodeImpl.right() instanceof BddAllOrNothing rightNode && rightNode.isNothing()) { + matList.add(env.mappingAtomType(bddNodeImpl.atom())); + return collectBddMappingAtomicTypesInUnion(env, bddNodeImpl.middle(), top, matList); + } + + return false; + } } diff --git a/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNode.java b/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNode.java index ee64fef97e73..c4c61efede1a 100644 --- a/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNode.java +++ b/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNode.java @@ -34,9 +34,9 @@ static BddNode create(Atom atom, Bdd left, Bdd middle, Bdd right) { } private static boolean isSimpleNode(Bdd left, Bdd middle, Bdd right) { - return left instanceof AllOrNothingSubtype leftNode && leftNode.isAllSubtype() && - middle instanceof AllOrNothingSubtype middleNode && middleNode.isNothingSubtype() && - right instanceof AllOrNothingSubtype rightNode && rightNode.isNothingSubtype(); + return left instanceof BddAllOrNothing leftNode && leftNode.isAll() && + middle instanceof BddAllOrNothing middleNode && middleNode.isNothing() && + right instanceof BddAllOrNothing rightNode && rightNode.isNothing(); } Atom atom(); diff --git a/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNodeImpl.java b/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNodeImpl.java index 760503d64efd..f2bea68b01ef 100644 --- a/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNodeImpl.java +++ b/semtypes/src/main/java/io/ballerina/types/subtypedata/BddNodeImpl.java @@ -29,6 +29,6 @@ * @param right path that include this node's atom negatively * @since 2201.10.0 */ -record BddNodeImpl(Atom atom, Bdd left, Bdd middle, Bdd right) implements BddNode { +public record BddNodeImpl(Atom atom, Bdd left, Bdd middle, Bdd right) implements BddNode { }