From a7d73c76dcd6d84b39e4799f0a344cb257c8935e Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Tue, 12 Dec 2023 11:30:22 +0530 Subject: [PATCH 01/10] Fix isolation analysis for params in start actions --- .../semantics/analyzer/IsolationAnalyzer.java | 314 +++++++++++++----- 1 file changed, 231 insertions(+), 83 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index 5718e6b33668..1f7ea96cf20e 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -27,6 +27,7 @@ import org.ballerinalang.model.tree.NodeKind; import org.ballerinalang.model.tree.expressions.ExpressionNode; import org.ballerinalang.model.tree.expressions.RecordLiteralNode; +import org.ballerinalang.model.types.TypeKind; import org.ballerinalang.util.diagnostic.DiagnosticErrorCode; import org.ballerinalang.util.diagnostic.DiagnosticHintCode; import org.ballerinalang.util.diagnostic.DiagnosticWarningCode; @@ -265,8 +266,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.Stack; @@ -293,10 +296,13 @@ public class IsolationAnalyzer extends BLangNodeVisitor { private boolean inferredIsolated = true; private boolean inLockStatement = false; + private boolean inIsolationStartAction = false; private final Stack copyInLockInfoStack = new Stack<>(); private final Stack> isolatedLetVarStack = new Stack<>(); private final Map isolationInferenceInfoMap = new HashMap<>(); private final Map arrowFunctionTempSymbolMap = new HashMap<>(); + private List listConstructorExprs; + private List mappingConstructorExprs; private IsolationAnalyzer(CompilerContext context) { context.put(ISOLATION_ANALYZER_KEY, this); @@ -1134,14 +1140,25 @@ public void visit(BLangRecordLiteral recordLiteral) { analyzeNode(keyValuePair.key.expr, env); } analyzeNode(keyValuePair.valueExpr, env); + addToMappingConstructorExprs(keyValuePair); } else if (field.getKind() == NodeKind.SIMPLE_VARIABLE_REF) { analyzeNode((BLangRecordLiteral.BLangRecordVarNameField) field, env); + addToMappingConstructorExprs(field); } else { - analyzeNode(((BLangRecordLiteral.BLangRecordSpreadOperatorField) field).expr, env); + analyzeNode((BLangRecordLiteral.BLangRecordSpreadOperatorField) field, env); } } } + @Override + public void visit(BLangRecordLiteral.BLangRecordSpreadOperatorField spreadOperatorField) { + analyzeNode(spreadOperatorField.expr, env); + NodeKind kind = spreadOperatorField.expr.getKind(); + if (!(kind == NodeKind.RECORD_LITERAL_EXPR || kind == NodeKind.TYPE_CONVERSION_EXPR)) { + addToMappingConstructorExprs(spreadOperatorField); + } + } + @Override public void visit(BLangTupleVarRef varRefExpr) { for (BLangExpression expression : varRefExpr.expressions) { @@ -1270,9 +1287,12 @@ public void visit(BLangSimpleVarRef varRefExpr) { } } } - if (!recordFieldDefaultValue && !objectFieldDefaultValueRequiringIsolation && enclInvokable != null && isReferenceToVarDefinedInSameInvokable(symbol.owner, enclInvokable.symbol)) { + if (this.inIsolationStartAction + && !isSubtypeOfReadOnlyOrIsolatedObjectOrInferableObject(symbol.owner, symbol.getType())) { + inferredIsolated = false; + } return; } @@ -1611,10 +1631,18 @@ public void visit(BLangLetExpression letExpr) { @Override public void visit(BLangListConstructorExpr listConstructorExpr) { for (BLangExpression expr : listConstructorExpr.exprs) { - if (expr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { - expr = ((BLangListConstructorExpr.BLangListConstructorSpreadOpExpr) expr).expr; - } analyzeNode(expr, env); + if (!(expr instanceof BLangListConstructorExpr.BLangListConstructorSpreadOpExpr)){ + addToListConstructorExprs(expr); + } + } + } + + @Override + public void visit(BLangListConstructorExpr.BLangListConstructorSpreadOpExpr listConstructorSpreadOpExpr) { + analyzeNode(listConstructorSpreadOpExpr.expr, env); + if (!(listConstructorSpreadOpExpr.expr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR)) { + addToListConstructorExprs(listConstructorSpreadOpExpr); } } @@ -2079,7 +2107,10 @@ private void analyzeInvocation(BLangInvocation invocationExpr) { } if (isolatedFunctionCall) { + boolean prevInIsolationStartAction = this.inIsolationStartAction; + this.inIsolationStartAction = inStartAction; analyzeArgIsolatedness(invocationExpr, requiredArgs, restArgs, symbol, expectsIsolation); + this.inIsolationStartAction = prevInIsolationStartAction; return; } @@ -2308,112 +2339,214 @@ private void analyzeArgIsolatedness(BLangInvocation invocationExpr, List memberTypes = tupleType.getTupleTypes(); + if (varArgType.tag == TypeTags.ARRAY || varArgType.tag == TypeTags.TUPLE) { + analyzeListConstructorRestArgs(invocationExpr, symbol, expectsIsolation, params, + paramsCount, reqArgCount, varArg, varArgType, varArgPos); + this.listConstructorExprs = null; + return; + } + analyzeMappingConstructorRestArgs(invocationExpr, symbol, expectsIsolation, params, + paramsCount, reqArgCount, varArg, varArgType, varArgPos); + this.mappingConstructorExprs = null; + return; + } + } - BLangExpression varArgExpr = varArg.expr; - boolean listConstrVarArg = varArgExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR; - BLangListConstructorExpr listConstructorExpr = listConstrVarArg ? - (BLangListConstructorExpr) varArgExpr : null; + if (!Symbols.isFlagOn(symbol.restParam.flags, Flags.ISOLATED_PARAM)) { + for (BLangExpression restArg : restArgs) { + analyzeNode(restArg, env); + } + return; + } - if (!listConstrVarArg) { - analyzeNode(varArg, env); - } + // Args for rest param provided as both individual args and vararg. + analyzeRestArgsForRestParam(invocationExpr, restArgs, symbol, expectsIsolation); + } - int tupleIndex = 0; - for (int i = reqArgCount; i < paramsCount; i++) { - if (!Symbols.isFlagOn(params.get(i).flags, Flags.ISOLATED_PARAM)) { - if (listConstrVarArg) { - analyzeNode(listConstructorExpr.exprs.get(tupleIndex), env); + private void analyzeMappingConstructorRestArgs(BLangInvocation invocationExpr, BInvokableSymbol symbol, + boolean expectsIsolation, List params, int paramsCount, + int reqArgCount, BLangRestArgsExpression varArg, BType varArgType, + Location varArgPos) { + BLangExpression varArgExpr = varArg.expr; + if (varArgType.tag != TypeTags.RECORD) { + return; + } + + // type cast required for rest args as record literal + boolean recordLiteralVarArg = varArgExpr.getKind() == NodeKind.TYPE_CONVERSION_EXPR; + BLangRecordLiteral recordLiteral = recordLiteralVarArg ? + (BLangRecordLiteral) ((BLangTypeConversionExpr) varArgExpr).expr : null; + + if (!recordLiteralVarArg) { + analyzeNode(varArg, env); + return; + } + this.mappingConstructorExprs = new ArrayList<>(); + analyzeNode(recordLiteral, env); + + for (int i = reqArgCount; i < paramsCount; i++) { + BVarSymbol param = params.get(i); + if (Symbols.isFlagOn(param.flags, Flags.ISOLATED_PARAM)) { + BLangExpression arg = null; + for (RecordLiteralNode.RecordField recordField: mappingConstructorExprs) { + if (recordField.isKeyValueField()) { + BLangRecordLiteral.BLangRecordKeyValueField keyValueField = + (BLangRecordLiteral.BLangRecordKeyValueField) recordField; + if (keyValueField.key.fieldSymbol.name.value.equals(param.name.value)) { + arg = keyValueField.valueExpr; + break; + } + } else if (recordField.getKind() == NodeKind.SIMPLE_VARIABLE_REF) { + BLangRecordLiteral.BLangRecordVarNameField varRefRecordField = + ((BLangRecordLiteral.BLangRecordVarNameField) recordField); + if (varRefRecordField.symbol.name.value.equals(param.name.value)) { + arg = varRefRecordField; + break; + } + } else { + BLangRecordLiteral.BLangRecordSpreadOperatorField spreadOpField = + (BLangRecordLiteral.BLangRecordSpreadOperatorField) recordField; + BVarSymbol varRefSymbol = (BVarSymbol) ((BLangSimpleVarRef) spreadOpField.expr).symbol; + BRecordType recordType = (BRecordType) Types.getReferredType(varRefSymbol.type); + Optional matchingField = recordType.fields.keySet() + .stream().filter(x -> x.equals(param.name.value)).findFirst(); + if (matchingField.isPresent()) { + arg = spreadOpField.expr; + break; } - tupleIndex++; - continue; } + } + analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); + BType type = Types.getReferredType(arg.getBType()); + handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, + type, varArgPos); + } + } + } - BType type = memberTypes.get(tupleIndex); + private void analyzeListConstructorRestArgs(BLangInvocation invocationExpr, BInvokableSymbol symbol, + boolean expectsIsolation, List params, int paramsCount, + int reqArgCount, BLangRestArgsExpression varArg, BType varArgType, + Location varArgPos) { + BTupleType tupleType = varArgType.tag == TypeTags.ARRAY ? + getRepresentativeTupleTypeForRemainingArgs(paramsCount, reqArgCount, (BArrayType) varArgType) : + (BTupleType) varArgType; - BLangExpression arg = null; - if (listConstrVarArg) { - arg = listConstructorExpr.exprs.get(tupleIndex); - analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); - type = arg.getBType(); - } + List memberTypes = tupleType.getTupleTypes(); - handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, - type, varArgPos); - tupleIndex++; - } + BLangExpression varArgExpr = varArg.expr; + boolean listConstrVarArg = varArgExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR; + BLangListConstructorExpr listConstructorExpr = listConstrVarArg ? + (BLangListConstructorExpr) varArgExpr : null; - BVarSymbol restParam = symbol.restParam; + if (!listConstrVarArg) { + analyzeNode(varArg, env); + } else { + this.listConstructorExprs = new ArrayList<>(); + analyzeNode(listConstructorExpr, env); + } - if (restParam == null) { - return; - } + int tupleIndex = 0; + int pointer = 0; + for (int i = reqArgCount; i < paramsCount; i++) { + if (Symbols.isFlagOn(params.get(i).flags, Flags.ISOLATED_PARAM)) { + BType type = memberTypes.get(tupleIndex); + + BLangExpression arg = null; + if (listConstrVarArg) { + // find the appropriate arg from the list constructor expr - if (!Symbols.isFlagOn(restParam.flags, Flags.ISOLATED_PARAM)) { - if (listConstructorExpr == null) { - return; + for (int j = pointer; j < listConstructorExprs.size(); j++) { + BLangExpression argExpr = listConstructorExprs.get(j); + if (!(argExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP)) { + pointer++; + continue; + } + BType argBType = Types.getReferredType( + ((BLangListConstructorExpr.BLangListConstructorSpreadOpExpr)argExpr).expr.getBType()); + int size = 0; + if (argBType.getKind() == TypeKind.ARRAY) { + size = ((BArrayType) argBType).getSize(); + } + if (argBType.getKind() == TypeKind.TUPLE) { + size = ((BTupleType) argBType).getTupleTypes().size(); + } + if (size + j > tupleIndex) { + break; + } + if (size + j == tupleIndex) { + pointer++; + break; + } + pointer++; } - - List exprs = listConstructorExpr.exprs; - for (int i = tupleIndex; i < exprs.size(); i++) { - analyzeNode(exprs.get(i), env); + arg = listConstructorExprs.get(pointer); + if (arg.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { + arg = ((BLangListConstructorExpr.BLangListConstructorSpreadOpExpr) arg).expr; + } + analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); + type = Types.getReferredType(arg.getBType()); + if (type.getKind() == TypeKind.ARRAY) { // do we really need this? + type = ((BArrayType) type).eType; + } + if (type.getKind() == TypeKind.TUPLE) { + type = ((BTupleType) type).getTupleTypes().get(tupleIndex - pointer); } - return; } - int memberTypeCount = memberTypes.size(); - if (tupleIndex < memberTypeCount) { - for (int i = tupleIndex; i < memberTypeCount; i++) { - BType type = memberTypes.get(i); - BLangExpression arg = null; - if (listConstrVarArg) { - arg = listConstructorExpr.exprs.get(i); - analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); - type = arg.getBType(); - } + handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, + type, varArgPos); + } + tupleIndex++; + } - handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, - type, varArgPos); - } - } + BVarSymbol restParam = symbol.restParam; - if (listConstrVarArg) { - List exprs = listConstructorExpr.exprs; - for (int i = tupleIndex; i < exprs.size(); i++) { - BLangExpression arg = exprs.get(i); - analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); + if (restParam == null) { + return; + } - handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, - arg.getBType(), varArgPos); - } - return; - } + if (!Symbols.isFlagOn(restParam.flags, Flags.ISOLATED_PARAM)) { + return; + } - BType tupleRestType = tupleType.restType; - if (tupleRestType == null) { - return; + // isolated rest params are handled in below + // need to revisit this logic if we are to implement isolated rest params in language libs + int memberTypeCount = memberTypes.size(); + if (tupleIndex < memberTypeCount) { + for (int i = tupleIndex; i < memberTypeCount; i++) { + BType type = memberTypes.get(i); + BLangExpression arg = null; + if (listConstrVarArg) { + arg = listConstructorExpr.exprs.get(i); + analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); + type = arg.getBType(); } - handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, null, expectsIsolation, - tupleRestType, varArgPos); - - return; + handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, + type, varArgPos); } } - if (!Symbols.isFlagOn(symbol.restParam.flags, Flags.ISOLATED_PARAM)) { - for (BLangExpression restArg : restArgs) { - analyzeNode(restArg, env); + if (listConstrVarArg) { + List exprs = listConstructorExpr.exprs; + for (int i = tupleIndex; i < exprs.size(); i++) { + BLangExpression arg = exprs.get(i); + analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); + + handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, + arg.getBType(), varArgPos); } return; } - // Args for rest param provided as both individual args and vararg. - analyzeRestArgsForRestParam(invocationExpr, restArgs, symbol, expectsIsolation); + BType tupleRestType = tupleType.restType; + if (tupleRestType == null) { + return; + } + + handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, null, expectsIsolation, + tupleRestType, varArgPos); } private BTupleType getRepresentativeTupleTypeForRemainingArgs(int paramCount, int reqArgCount, @@ -3558,6 +3691,21 @@ private void markFunctionDependentlyIsolatedOnFunction(BLangInvokableNode enclIn isolationInferenceInfoMap.get(enclInvokableSymbol).dependsOnFunctions.add(symbol); } + + private void addToMappingConstructorExprs(RecordLiteralNode.RecordField field) { + // need to collect only args given as rest args + if (this.inIsolationStartAction && this.mappingConstructorExprs != null) { + this.mappingConstructorExprs.add(field); + } + } + + private void addToListConstructorExprs(BLangExpression expr) { + // need to collect only args given as rest args + if (this.inIsolationStartAction && this.listConstructorExprs != null) { + this.listConstructorExprs.add(expr); + } + } + private boolean isNotInArrowFunctionBody(SymbolEnv env) { return env.node.getKind() != NodeKind.EXPR_FUNCTION_BODY || env.enclEnv.node.getKind() != NodeKind.ARROW_EXPR; } From 7e2f5e22df2019d7de2b3d7e9baa6c27d02cfd34 Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Tue, 12 Dec 2023 11:30:49 +0530 Subject: [PATCH 02/10] Add isolation warning tests --- .../test/isolation/IsolationWarningTest.java | 152 +++++- ...isolation_warnings_for_service_methods.bal | 461 +++++++++++++++++- 2 files changed, 590 insertions(+), 23 deletions(-) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/isolation/IsolationWarningTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/isolation/IsolationWarningTest.java index 45313c669723..2c5479d5259c 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/isolation/IsolationWarningTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/isolation/IsolationWarningTest.java @@ -46,28 +46,136 @@ public void testIsolationWarnings() { int i = 0; validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 26, 5); validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 30, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 43, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 47, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 62, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 66, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 79, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 83, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 101, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 105, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 118, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 122, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 137, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 141, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 154, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 158, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 176, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 180, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 193, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 197, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 211, 5); - validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 215, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 228, 5); - validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 232, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 39, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 43, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 47, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 51, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 55, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 59, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 63, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 67, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 71, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 79, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 83, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 93, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 97, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 101, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 105, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 109, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 113, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 117, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 121, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 125, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 134, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 138, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 146, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 150, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 154, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 158, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 162, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 166, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 170, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 174, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 178, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 187, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 191, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 201, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 205, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 209, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 213, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 217, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 221, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 225, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 229, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 233, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 245, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 249, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 258, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 262, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 266, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 270, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 274, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 278, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 282, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 286, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 290, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 298, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 302, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 312, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 316, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 320, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 324, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 328, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 332, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 336, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 340, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 344, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 353, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 357, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 365, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 369, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 373, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 377, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 381, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 385, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 389, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 393, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 397, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 406, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 410, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 420, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 424, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 428, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 432, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 436, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 440, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 444, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 448, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 452, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 464, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_HINT, 468, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 477, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 481, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 485, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 489, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 493, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 497, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 501, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 505, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 509, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 517, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 521, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 531, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 535, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 539, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 543, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 547, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 551, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 555, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 559, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 563, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 571, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 575, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 583, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 587, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 591, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 595, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 599, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 603, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 607, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 611, 5); + validateHint(result, i++, NON_ISOLATED_METHOD_HINT, 615, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 624, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 628, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 638, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 642, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 646, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 650, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 654, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 658, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 662, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 666, 5); + validateHint(result, i++, NON_ISOLATED_SERVICE_AND_METHOD_HINT, 670, 5); assertEquals(result.getHintCount(), i); LineRange lineRange = result.getDiagnostics()[0].location().lineRange(); diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_warnings_for_service_methods.bal b/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_warnings_for_service_methods.bal index d0918ade8590..bf3467ea7b5c 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_warnings_for_service_methods.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_warnings_for_service_methods.bal @@ -14,7 +14,7 @@ // specific language governing permissions and limitations // under the License. -int nonIsolatedVar = 0; +int nonIsolatedVar = 0; //////////////////// Service Declarations //////////////////// @@ -35,6 +35,42 @@ service on new Listener() { function func() { } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } isolated service "ser2" on new Listener() { @@ -53,6 +89,42 @@ isolated service "ser2" on new Listener() { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } // Inferred isolated. @@ -70,6 +142,42 @@ service "ser3" on new Listener() { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } service "ser4" on new Listener() { @@ -89,6 +197,42 @@ service "ser4" on new Listener() { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } //////////////////// Service Classes //////////////////// @@ -110,6 +254,42 @@ service class Serv1 { function func() { } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } isolated service class Serv2 { @@ -128,6 +308,42 @@ isolated service class Serv2 { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } // Inferred isolated. @@ -145,6 +361,42 @@ service class Serv3 { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } service class Serv4 { @@ -164,6 +416,42 @@ service class Serv4 { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } } //////////////////// Service Object Constructors //////////////////// @@ -185,6 +473,42 @@ var s1 = service object { function func() { } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } }; var s2 = isolated service object { @@ -203,6 +527,42 @@ var s2 = isolated service object { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } }; var s3 = service object { @@ -219,6 +579,42 @@ var s3 = service object { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } }; service object {} s4 = service object { @@ -238,6 +634,42 @@ service object {} s4 = service object { function func() { nonIsolatedFunc(); } + + resource function post bar(string[] mutableVal) { + _ = start mutableValueAccess(mutableVal); + } + + resource function post bas([string[], string[], string[]] args) { + _ = start passParamsAsRestArgs(...args); + } + + resource function post baz(string[] arg1, string[] arg2, string[] arg3) { + _ = start passParamsAsRestArgs(...[arg1, arg2, arg3]); + } + + resource function post qux(string[] arg1, string[] arg2, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[arg1, arg2, ...restArgs]); + } + + resource function post quxx([string[], string[]] args, string[]... restArgs) { + _ = start passRequiredArgsAndRestArgs(...[...args, ...restArgs]); + } + + resource function post quxxx(string[] arg1, string[] arg2, string[] arg3) { + _ = start passRestArgsAsArgs(arg1, arg2, arg3); + } + + resource function post path(T1 t1) { + _ = start passParamsAsRestArgs(t1.arg1, [], []); + } + + resource function post path2(T1 t1, T2 t2) { + _ = start passParamsAsRestArgs(...{...t1, ...t2, arg3: []}); + } + + resource function post path3(T3 t3) { + _ = start passParamsAsRestArgs(...{...{...{...t3}}}); + } }; function nonIsolatedFunc() { @@ -315,6 +747,33 @@ var s6 = isolated service object { } }; +isolated function mutableValueAccess(string[] value) { +} + +isolated function passParamsAsRestArgs(string[] arg1, string[] arg2, string[] arg3) { +} + +isolated function passRequiredArgsAndRestArgs(string[] arg1, string[] arg2, string[]... restArg) { +} + +isolated function passRestArgsAsArgs(string[]... restArg) { +} + + +type T1 record {| + string[] arg1; +|}; + +type T2 record {| + string[] arg2; +|}; + +type T3 record {| + *T1; + *T2; + string[] arg3; +|}; + public class Listener { public isolated function 'start() returns error? { return; From 5572bd487648d4c4d41fe033d92d9c0eec87308d Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Thu, 14 Dec 2023 09:44:49 +0530 Subject: [PATCH 03/10] Fix checkstyles failures --- .../compiler/semantics/analyzer/IsolationAnalyzer.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index 1f7ea96cf20e..7b09ec23a173 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -266,7 +266,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -1632,7 +1631,7 @@ public void visit(BLangLetExpression letExpr) { public void visit(BLangListConstructorExpr listConstructorExpr) { for (BLangExpression expr : listConstructorExpr.exprs) { analyzeNode(expr, env); - if (!(expr instanceof BLangListConstructorExpr.BLangListConstructorSpreadOpExpr)){ + if (!(expr instanceof BLangListConstructorExpr.BLangListConstructorSpreadOpExpr)) { addToListConstructorExprs(expr); } } @@ -2463,7 +2462,7 @@ private void analyzeListConstructorRestArgs(BLangInvocation invocationExpr, BInv continue; } BType argBType = Types.getReferredType( - ((BLangListConstructorExpr.BLangListConstructorSpreadOpExpr)argExpr).expr.getBType()); + ((BLangListConstructorExpr.BLangListConstructorSpreadOpExpr) argExpr).expr.getBType()); int size = 0; if (argBType.getKind() == TypeKind.ARRAY) { size = ((BArrayType) argBType).getSize(); From b6d69b0fcd28dbeba6562e006fb74914f23bcadb Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Fri, 2 Feb 2024 22:56:09 +0530 Subject: [PATCH 04/10] Fix not inferring dependentOnFunctionCallArg exprs --- .../compiler/semantics/analyzer/IsolationAnalyzer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index 7b09ec23a173..c5075d11097e 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -4272,7 +4272,8 @@ private boolean inferFunctionIsolation(BSymbol symbol, IsolationInferenceInfo fu } for (BLangExpression dependsOnArg : functionIsolationInferenceInfo.dependsOnFuncCallArgExprs) { - if (!isIsolatedExpression(dependsOnArg)) { + if (!isIsolatedExpression(dependsOnArg, false, true, new ArrayList<>(), true, + publiclyExposedObjectTypes, classDefinitions, moduleLevelVariables, new HashSet<>())) { return false; } } From 68707cd8b69f978b04c18549fdc94f406e6bbed8 Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Mon, 4 Mar 2024 11:51:12 +0530 Subject: [PATCH 05/10] Remove unreachable code lines --- .../semantics/analyzer/IsolationAnalyzer.java | 105 ++---------------- 1 file changed, 9 insertions(+), 96 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index c5075d11097e..2f319a24c65e 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -1288,7 +1288,7 @@ public void visit(BLangSimpleVarRef varRefExpr) { } if (!recordFieldDefaultValue && !objectFieldDefaultValueRequiringIsolation && enclInvokable != null && isReferenceToVarDefinedInSameInvokable(symbol.owner, enclInvokable.symbol)) { - if (this.inIsolationStartAction + if (this.inIsolationStartAction && !isSubtypeOfReadOnlyOrIsolatedObjectOrInferableObject(symbol.owner, symbol.getType())) { inferredIsolated = false; } @@ -1547,7 +1547,7 @@ public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessIn analyzeNode(resourceAccessInvocation.resourceAccessPathSegments, env); analyzeInvocation(resourceAccessInvocation); } - + @Override public void visit(BLangTypeInit typeInitExpr) { BInvokableSymbol initInvocationSymbol = @@ -1631,18 +1631,13 @@ public void visit(BLangLetExpression letExpr) { public void visit(BLangListConstructorExpr listConstructorExpr) { for (BLangExpression expr : listConstructorExpr.exprs) { analyzeNode(expr, env); - if (!(expr instanceof BLangListConstructorExpr.BLangListConstructorSpreadOpExpr)) { - addToListConstructorExprs(expr); - } + addToListConstructorExprs(expr); } } @Override public void visit(BLangListConstructorExpr.BLangListConstructorSpreadOpExpr listConstructorSpreadOpExpr) { analyzeNode(listConstructorSpreadOpExpr.expr, env); - if (!(listConstructorSpreadOpExpr.expr.getKind() == NodeKind.LIST_CONSTRUCTOR_EXPR)) { - addToListConstructorExprs(listConstructorSpreadOpExpr); - } } @Override @@ -2339,12 +2334,12 @@ private void analyzeArgIsolatedness(BLangInvocation invocationExpr, List exprs = listConstructorExpr.exprs; - for (int i = tupleIndex; i < exprs.size(); i++) { - BLangExpression arg = exprs.get(i); - analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); - - handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, - arg.getBType(), varArgPos); - } - return; - } - - BType tupleRestType = tupleType.restType; - if (tupleRestType == null) { - return; - } - - handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, null, expectsIsolation, - tupleRestType, varArgPos); } private BTupleType getRepresentativeTupleTypeForRemainingArgs(int paramCount, int reqArgCount, @@ -2564,35 +2506,6 @@ private BTupleType getRepresentativeTupleTypeForRemainingArgs(int paramCount, in return new BTupleType(members); } - private void analyzeRestArgsForRestParam(BLangInvocation invocationExpr, List restArgs, - BInvokableSymbol symbol, boolean expectsIsolation) { - if (Symbols.isFlagOn(((BArrayType) symbol.restParam.type).eType.flags, Flags.ISOLATED)) { - for (BLangExpression restArg : restArgs) { - analyzeNode(restArg, env); - } - return; - } - - for (BLangExpression restArg : restArgs) { - analyzeAndSetArrowFuncFlagForIsolatedParamArg(restArg); - } - - int size = restArgs.size(); - BLangExpression lastArg = restArgs.get(size - 1); - - boolean lastArgIsVarArg = lastArg.getKind() == NodeKind.REST_ARGS_EXPR; - - for (int i = 0; i < (lastArgIsVarArg ? size - 1 : size); i++) { - BLangExpression arg = restArgs.get(i); - handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, - arg.getBType(), arg.pos); - } - - if (lastArgIsVarArg) { - analyzeVarArgIsolatedness(invocationExpr, (BLangRestArgsExpression) lastArg, lastArg.pos, expectsIsolation); - } - } - private void analyzeVarArgIsolatedness(BLangInvocation invocationExpr, BLangRestArgsExpression restArgsExpression, Location pos, boolean expectsIsolation) { BLangExpression expr = restArgsExpression.expr; @@ -3693,18 +3606,18 @@ private void markFunctionDependentlyIsolatedOnFunction(BLangInvokableNode enclIn private void addToMappingConstructorExprs(RecordLiteralNode.RecordField field) { // need to collect only args given as rest args - if (this.inIsolationStartAction && this.mappingConstructorExprs != null) { + if (this.mappingConstructorExprs != null) { this.mappingConstructorExprs.add(field); } } - + private void addToListConstructorExprs(BLangExpression expr) { // need to collect only args given as rest args - if (this.inIsolationStartAction && this.listConstructorExprs != null) { + if (this.listConstructorExprs != null) { this.listConstructorExprs.add(expr); } } - + private boolean isNotInArrowFunctionBody(SymbolEnv env) { return env.node.getKind() != NodeKind.EXPR_FUNCTION_BODY || env.enclEnv.node.getKind() != NodeKind.ARROW_EXPR; } From 780c45f216f2ae4bbcc9c37ca1eb098039539f03 Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Mon, 4 Mar 2024 11:51:48 +0530 Subject: [PATCH 06/10] Add tests for isolation analysis --- .../langlib/test/IsolatedParamTest.java | 5 +++++ .../isolated-param/isolated_param_negative.bal | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java index 82d497652ff9..07344a9a638a 100644 --- a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java +++ b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java @@ -73,6 +73,11 @@ public void testIsolatedParamNegative() { validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 51, 59); validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 57, 82); validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 65, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 66, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 67, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 81, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 82, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 83, 22); Assert.assertEquals(result.getErrorCount(), index); } diff --git a/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal b/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal index 08e5a2c50ea6..1b15cb8c0145 100644 --- a/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal +++ b/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal @@ -63,4 +63,22 @@ isolated function testInvalidNonIsolatedFuncArgInFixedLengthArrayRestArg() { int[] marks = [75, 80, 45, 90]; (function (int x) returns boolean)[1] fns = [x => x > 79]; _ = marks.filter(...fns); + _ = marks.filter(...[...fns]); + _ = marks.filter(...[...[...fns]]); +} + +type Rec record {| + function(int) returns (boolean) func; +|}; + +isolated function testInvalidNonIsolatedFuncArgAsMappingsInFixedLengthArrayRestArg() { + int[] marks = [75, 80, 45, 90]; + (function (int x) returns boolean) func = x => x > 79; + Rec rec = { + func + }; + _ = marks.filter(...rec); + _ = marks.filter(...{...rec}); + _ = marks.filter(...{func}); + _ = marks.filter(...{func: func}); } From 89c60562ae17480f3e4f5b8850a1f51cf55e05e9 Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Mon, 11 Mar 2024 08:51:33 +0530 Subject: [PATCH 07/10] Add more tests for isolation analysis --- .../semantics/analyzer/IsolationAnalyzer.java | 1 - .../ballerinalang/langlib/test/IsolatedParamTest.java | 11 ++++++++--- .../isolated-param/isolated_param_negative.bal | 7 +++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index 2f319a24c65e..ddeb1c909476 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -2448,7 +2448,6 @@ private void analyzeListConstructorRestArgs(BLangInvocation invocationExpr, BInv for (int j = pointer; j < listConstructorExprs.size(); j++) { BLangExpression argExpr = listConstructorExprs.get(j); if (!(argExpr.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP)) { - pointer++; continue; } BType argBType = Types.getReferredType( diff --git a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java index 07344a9a638a..a0caca41bdb2 100644 --- a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java +++ b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java @@ -75,9 +75,14 @@ public void testIsolatedParamNegative() { validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 65, 22); validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 66, 22); validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 67, 22); - validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 81, 22); - validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 82, 22); - validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 83, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 68, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 71, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 72, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 73, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 87, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 88, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 89, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 90, 22); Assert.assertEquals(result.getErrorCount(), index); } diff --git a/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal b/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal index 1b15cb8c0145..2d6600bf825d 100644 --- a/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal +++ b/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal @@ -65,6 +65,12 @@ isolated function testInvalidNonIsolatedFuncArgInFixedLengthArrayRestArg() { _ = marks.filter(...fns); _ = marks.filter(...[...fns]); _ = marks.filter(...[...[...fns]]); + _ = marks.filter(...[fns[0]]); + + [(function (int x) returns boolean)] fnTuple = [x => x > 79]; + _ = marks.filter(...fnTuple); + _ = marks.filter(...[...fnTuple]); + _ = marks.filter(...[fnTuple[0]]); } type Rec record {| @@ -81,4 +87,5 @@ isolated function testInvalidNonIsolatedFuncArgAsMappingsInFixedLengthArrayRestA _ = marks.filter(...{...rec}); _ = marks.filter(...{func}); _ = marks.filter(...{func: func}); + _ = marks.filter(...{...{...rec}}); } From 96772a424b93e6ad56fa2e238678272c2ef0bcd6 Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Thu, 14 Mar 2024 12:24:26 +0530 Subject: [PATCH 08/10] Address review suggestions --- .../semantics/analyzer/IsolationAnalyzer.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index ddeb1c909476..45378c7e7250 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -295,7 +295,7 @@ public class IsolationAnalyzer extends BLangNodeVisitor { private boolean inferredIsolated = true; private boolean inLockStatement = false; - private boolean inIsolationStartAction = false; + private boolean inIsolatedStartAction = false; private final Stack copyInLockInfoStack = new Stack<>(); private final Stack> isolatedLetVarStack = new Stack<>(); private final Map isolationInferenceInfoMap = new HashMap<>(); @@ -1288,7 +1288,7 @@ public void visit(BLangSimpleVarRef varRefExpr) { } if (!recordFieldDefaultValue && !objectFieldDefaultValueRequiringIsolation && enclInvokable != null && isReferenceToVarDefinedInSameInvokable(symbol.owner, enclInvokable.symbol)) { - if (this.inIsolationStartAction + if (this.inIsolatedStartAction && !isSubtypeOfReadOnlyOrIsolatedObjectOrInferableObject(symbol.owner, symbol.getType())) { inferredIsolated = false; } @@ -2101,10 +2101,10 @@ private void analyzeInvocation(BLangInvocation invocationExpr) { } if (isolatedFunctionCall) { - boolean prevInIsolationStartAction = this.inIsolationStartAction; - this.inIsolationStartAction = inStartAction; + boolean prevInIsolationStartAction = this.inIsolatedStartAction; + this.inIsolatedStartAction = inStartAction; analyzeArgIsolatedness(invocationExpr, requiredArgs, restArgs, symbol, expectsIsolation); - this.inIsolationStartAction = prevInIsolationStartAction; + this.inIsolatedStartAction = prevInIsolationStartAction; return; } @@ -2358,9 +2358,6 @@ private void analyzeMappingConstructorRestArgs(BLangInvocation invocationExpr, B int reqArgCount, BLangRestArgsExpression varArg, BType varArgType, Location varArgPos) { BLangExpression varArgExpr = varArg.expr; - if (varArgType.tag != TypeTags.RECORD) { - return; - } // type cast required for rest args as record literal boolean recordLiteralVarArg = varArgExpr.getKind() == NodeKind.TYPE_CONVERSION_EXPR; @@ -2462,11 +2459,6 @@ private void analyzeListConstructorRestArgs(BLangInvocation invocationExpr, BInv if (size + j > tupleIndex) { break; } - if (size + j == tupleIndex) { - pointer++; - break; - } - pointer++; } arg = listConstructorExprs.get(pointer); if (arg.getKind() == NodeKind.LIST_CONSTRUCTOR_SPREAD_OP) { From 3f069ce069ced6817f05c87fb0c77f5f82867da4 Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Mon, 18 Mar 2024 09:39:35 +0530 Subject: [PATCH 09/10] Add tests for isolation analysis --- .../test-src/isolation-analysis/isolation_analysis.bal | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_analysis.bal b/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_analysis.bal index 8297d860e444..26c56f8aa59e 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_analysis.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/isolation-analysis/isolation_analysis.bal @@ -610,3 +610,11 @@ isolated function assertEquality(any|error expected, any|error actual) { } type IsolatedFunction isolated function () returns int; + +isolated function func() { + _ = start process(getMutableIntArray()); +} + +isolated function process(int[] array) { + +} From d7e77290ba3bfc7bf08e9e6703fee8cc132aeea9 Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Tue, 19 Mar 2024 15:20:58 +0530 Subject: [PATCH 10/10] Hanlde record literals within group exprs --- .../semantics/analyzer/IsolationAnalyzer.java | 44 ++++++++++++------- .../langlib/test/IsolatedParamTest.java | 1 + .../isolated_param_negative.bal | 1 + 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index 45378c7e7250..106a0fc34818 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -1153,7 +1153,8 @@ public void visit(BLangRecordLiteral recordLiteral) { public void visit(BLangRecordLiteral.BLangRecordSpreadOperatorField spreadOperatorField) { analyzeNode(spreadOperatorField.expr, env); NodeKind kind = spreadOperatorField.expr.getKind(); - if (!(kind == NodeKind.RECORD_LITERAL_EXPR || kind == NodeKind.TYPE_CONVERSION_EXPR)) { + if (!(kind == NodeKind.RECORD_LITERAL_EXPR || kind == NodeKind.TYPE_CONVERSION_EXPR + || kind == NodeKind.GROUP_EXPR)) { addToMappingConstructorExprs(spreadOperatorField); } } @@ -2334,13 +2335,13 @@ private void analyzeArgIsolatedness(BLangInvocation invocationExpr, List params, int paramsCount, - int reqArgCount, BLangRestArgsExpression varArg, BType varArgType, + int reqArgCount, BLangRestArgsExpression varArg, Location varArgPos) { BLangExpression varArgExpr = varArg.expr; - // type cast required for rest args as record literal - boolean recordLiteralVarArg = varArgExpr.getKind() == NodeKind.TYPE_CONVERSION_EXPR; - BLangRecordLiteral recordLiteral = recordLiteralVarArg ? - (BLangRecordLiteral) ((BLangTypeConversionExpr) varArgExpr).expr : null; - - if (!recordLiteralVarArg) { + BLangExpression recordLiteral = findRecordLiteral(varArgExpr); + if (!(recordLiteral instanceof BLangRecordLiteral)) { analyzeNode(varArg, env); return; } @@ -2375,12 +2372,14 @@ private void analyzeMappingConstructorRestArgs(BLangInvocation invocationExpr, B BVarSymbol param = params.get(i); if (Symbols.isFlagOn(param.flags, Flags.ISOLATED_PARAM)) { BLangExpression arg = null; + BType type = null; for (RecordLiteralNode.RecordField recordField: mappingConstructorExprs) { if (recordField.isKeyValueField()) { BLangRecordLiteral.BLangRecordKeyValueField keyValueField = (BLangRecordLiteral.BLangRecordKeyValueField) recordField; if (keyValueField.key.fieldSymbol.name.value.equals(param.name.value)) { arg = keyValueField.valueExpr; + type = Types.getReferredType(arg.getBType()); break; } } else if (recordField.getKind() == NodeKind.SIMPLE_VARIABLE_REF) { @@ -2388,6 +2387,7 @@ private void analyzeMappingConstructorRestArgs(BLangInvocation invocationExpr, B ((BLangRecordLiteral.BLangRecordVarNameField) recordField); if (varRefRecordField.symbol.name.value.equals(param.name.value)) { arg = varRefRecordField; + type = Types.getReferredType(arg.getBType()); break; } } else { @@ -2395,23 +2395,35 @@ private void analyzeMappingConstructorRestArgs(BLangInvocation invocationExpr, B (BLangRecordLiteral.BLangRecordSpreadOperatorField) recordField; BVarSymbol varRefSymbol = (BVarSymbol) ((BLangSimpleVarRef) spreadOpField.expr).symbol; BRecordType recordType = (BRecordType) Types.getReferredType(varRefSymbol.type); - Optional matchingField = recordType.fields.keySet() - .stream().filter(x -> x.equals(param.name.value)).findFirst(); + Optional matchingField = recordType.fields.entrySet().stream() + .filter(k -> k.getKey().equals(param.name.value)) + .map(Map.Entry::getValue) + .findFirst(); if (matchingField.isPresent()) { arg = spreadOpField.expr; + type = Types.getReferredType(matchingField.get().getType()); break; } } } analyzeAndSetArrowFuncFlagForIsolatedParamArg(arg); - BType type = Types.getReferredType(arg.getBType()); handleNonExplicitlyIsolatedArgForIsolatedParam(invocationExpr, arg, expectsIsolation, type, varArgPos); } } } - private void analyzeListConstructorRestArgs(BLangInvocation invocationExpr, BInvokableSymbol symbol, + private BLangExpression findRecordLiteral(BLangExpression expr) { + if (expr.getKind() == NodeKind.GROUP_EXPR) { + return findRecordLiteral(((BLangGroupExpr) expr).expression); + } + if (expr.getKind() == NodeKind.TYPE_CONVERSION_EXPR) { + return findRecordLiteral(((BLangTypeConversionExpr) expr).expr); + } + return expr; + } + + private void analyzeListConstructorRestArgs(BLangInvocation invocationExpr, boolean expectsIsolation, List params, int paramsCount, int reqArgCount, BLangRestArgsExpression varArg, BType varArgType, Location varArgPos) { diff --git a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java index a0caca41bdb2..f66dd26b38a8 100644 --- a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java +++ b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/IsolatedParamTest.java @@ -83,6 +83,7 @@ public void testIsolatedParamNegative() { validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 88, 22); validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 89, 22); validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 90, 22); + validateError(result, index++, NON_ISOLATED_ARG_FOR_ISOLATED_PARAM_ERROR, 91, 22); Assert.assertEquals(result.getErrorCount(), index); } diff --git a/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal b/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal index 2d6600bf825d..64420002e0c3 100644 --- a/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal +++ b/langlib/langlib-test/src/test/resources/test-src/isolated-param/isolated_param_negative.bal @@ -85,6 +85,7 @@ isolated function testInvalidNonIsolatedFuncArgAsMappingsInFixedLengthArrayRestA }; _ = marks.filter(...rec); _ = marks.filter(...{...rec}); + _ = marks.filter(...({...rec})); _ = marks.filter(...{func}); _ = marks.filter(...{func: func}); _ = marks.filter(...{...{...rec}});