From 3bb443377419fc8bab09684809d94d98fdd4eccf Mon Sep 17 00:00:00 2001 From: rdulmina Date: Fri, 20 Dec 2024 10:38:33 +0530 Subject: [PATCH] Fix issue #43715 --- .../semantics/analyzer/DataflowAnalyzer.java | 26 ++++++++++++++++++- ...orwardReferencingGlobalDefinitionTest.java | 2 ++ .../globalcycle/simpleProject/file02.bal | 6 +++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java index 673d2ebdfab1..c11b20df8945 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java @@ -273,6 +273,8 @@ public class DataflowAnalyzer extends BLangNodeVisitor { private Map unusedErrorVarsDeclaredWithVar; private Map unusedLocalVariables; private final Map symbolOwner; + private final Map dependsOnLambda; + private final Map invocationToDependent; private Map> globalNodeDependsOn; private Map> functionToDependency; private Map> possibleFailureUnInitVars; @@ -296,6 +298,8 @@ private DataflowAnalyzer(CompilerContext context) { this.globalVariableRefAnalyzer = GlobalVariableRefAnalyzer.getInstance(context); this.unusedLocalVariables = new HashMap<>(); this.symbolOwner = new HashMap<>(); + this.dependsOnLambda = new HashMap<>(); + this.invocationToDependent = new HashMap<>(); } public static DataflowAnalyzer getInstance(CompilerContext context) { @@ -355,6 +359,7 @@ public void visit(BLangPackage pkgNode) { } checkForUninitializedGlobalVars(pkgNode.globalVars); pkgNode.getTestablePkgs().forEach(testablePackage -> visit((BLangPackage) testablePackage)); + updateProvidersForLambdaInvocations(); this.globalVariableRefAnalyzer.analyzeAndReOrder(pkgNode, this.globalNodeDependsOn, this.symbolOwner); this.globalVariableRefAnalyzer.populateFunctionDependencies(this.functionToDependency, pkgNode.globalVars); pkgNode.globalVariableDependencies = globalVariableRefAnalyzer.getGlobalVariablesDependsOn(); @@ -369,6 +374,21 @@ public void visit(BLangPackage pkgNode) { pkgNode.completedPhases.add(CompilerPhase.DATAFLOW_ANALYZE); } + /** + * When seeing a lambda function expression, we do not add it as a provider to current dependent symbol. + * Instead, we need to add it as a provider when it is invoked. This method is used to update the providers + * for those invocations. + */ + private void updateProvidersForLambdaInvocations() { + for (Map.Entry entry : dependsOnLambda.entrySet()) { + BSymbol dependent= entry.getKey(); + BSymbol lambda = entry.getValue(); + if (invocationToDependent.containsKey(dependent) && globalNodeDependsOn.containsKey(dependent)) { + globalNodeDependsOn.get(dependent).add(lambda); + } + } + } + private void addModuleInitToSortedNodeList(BLangPackage pkgNode, List sortedListOfNodes) { for (TopLevelNode node : pkgNode.topLevelNodes) { if (isModuleInitFunction((BLangNode) node)) { @@ -1690,6 +1710,8 @@ public void visit(BLangInvocation invocationExpr) { BSymbol symbol = invocationExpr.symbol; this.unusedLocalVariables.remove(symbol); + invocationToDependent.put(symbol, this.currDependentSymbolDeque.peek()); + if (isFunctionOrMethodDefinedInCurrentModule(symbol.owner, env) && !isGlobalVarsInitialized(invocationExpr.pos, invocationExpr)) { checkVarRef(symbol, invocationExpr.pos); @@ -2131,7 +2153,9 @@ public void visit(BLangLambdaFunction bLangLambdaFunction) { BLangFunction funcNode = bLangLambdaFunction.function; SymbolEnv funcEnv = SymbolEnv.createFunctionEnv(funcNode, funcNode.symbol.scope, env); visitFunctionBodyWithDynamicEnv(funcNode, funcEnv); - recordGlobalVariableReferenceRelationship(funcNode.symbol); + if (isGlobalVarSymbol(funcNode.symbol)) { + dependsOnLambda.put(this.currDependentSymbolDeque.peek(), funcNode.symbol); + } } @Override diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java index 21671cfbea5e..6c91b867e4a5 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/variabledef/ForwardReferencingGlobalDefinitionTest.java @@ -43,6 +43,8 @@ public void globalDefinitionsWithCyclicReferences() { Assert.assertTrue(diagnostics.length > 0); BAssertUtil.validateError(resultNegativeCycleFound, 0, "illegal cyclic reference '[person, employee]'", 17, 1); BAssertUtil.validateError(resultNegativeCycleFound, 1, "illegal cyclic reference '[dep2, dep1]'", 24, 1); + BAssertUtil.validateError(resultNegativeCycleFound, 1, + "illegal cyclic reference '[lambdaFoo, $lambda$_0, myBool]'", 26, 1); } @Test(description = "Test re-ordering global variable initializations to satisfy dependency order") diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/globalcycle/simpleProject/file02.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/globalcycle/simpleProject/file02.bal index 7d7f17585980..d2061050fdfa 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/globalcycle/simpleProject/file02.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/globalcycle/simpleProject/file02.bal @@ -22,3 +22,9 @@ Person person = { [Employee, Person] pp2 = [employee, person]; int dep2 = dep1; + +function() returns boolean lambdaFoo = function() returns boolean { + return myBool; +}; + +boolean myBool = lambdaFoo();