From 948eec4e1d3f1521a1a1bdbde85491edeb1b20a8 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Tue, 4 Jun 2024 09:57:42 +0530 Subject: [PATCH 01/13] Reorder the desugaring of type definitions before the desugaring of global variables and configurables --- .../java/org/wso2/ballerinalang/compiler/desugar/Desugar.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 e9f6ed582a70..5d7bfa7110ca 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 @@ -794,6 +794,8 @@ public void visit(BLangPackage pkgNode) { pkgNode.constants = removeDuplicateConstants(pkgNode); + rewrite(pkgNode.typeDefinitions, env); + pkgNode.globalVars = desugarGlobalVariables(pkgNode, initFnBody); pkgNode.services.forEach(service -> serviceDesugar.engageCustomServiceDesugar(service, env)); @@ -806,7 +808,6 @@ public void visit(BLangPackage pkgNode) { //Sort type definitions with precedence pkgNode.typeDefinitions.sort(Comparator.comparing(t -> t.precedence)); - pkgNode.typeDefinitions = rewrite(pkgNode.typeDefinitions, env); pkgNode.xmlnsList = rewrite(pkgNode.xmlnsList, env); pkgNode.constants = rewrite(pkgNode.constants, env); pkgNode.globalVars = rewrite(pkgNode.globalVars, env); From 2a0b832a7dd6a0039581d8cec9d3f1a16aef51c3 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Tue, 4 Jun 2024 09:58:11 +0530 Subject: [PATCH 02/13] Add unit tests --- .../variabledef/configurable_var_decl.bal | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/configurable_var_decl.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/configurable_var_decl.bal index 3f3d5c6dfaf9..a4ad96e7ced4 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/configurable_var_decl.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/variabledef/configurable_var_decl.bal @@ -25,9 +25,22 @@ configurable UserInfo admin = { password: "password" }; +public type CustomConfiguration record { + string username; + string logLevel = "OFF"; +}; + +configurable CustomConfiguration customConfig1 = {username: "chiranS"}; + +configurable CustomConfiguration customConfig2 = {username: "chiranS", logLevel: "DEBUG"}; + function testConfigValue() { assertEquality("default", admin.username); assertEquality("password", admin.password); + assertEquality("chiranS", customConfig1.username); + assertEquality("OFF", customConfig1.logLevel); + assertEquality("chiranS", customConfig2.username); + assertEquality("DEBUG", customConfig2.logLevel); } function assertEquality(any|error expected, any|error actual) { From 29b8f599f53e11307e3c2001b11f3e905c05d4c6 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Wed, 5 Jun 2024 14:20:21 +0530 Subject: [PATCH 03/13] Fix review suggestion --- .../org/wso2/ballerinalang/compiler/desugar/Desugar.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 5d7bfa7110ca..58650d831354 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 @@ -794,8 +794,6 @@ public void visit(BLangPackage pkgNode) { pkgNode.constants = removeDuplicateConstants(pkgNode); - rewrite(pkgNode.typeDefinitions, env); - pkgNode.globalVars = desugarGlobalVariables(pkgNode, initFnBody); pkgNode.services.forEach(service -> serviceDesugar.engageCustomServiceDesugar(service, env)); @@ -808,6 +806,7 @@ public void visit(BLangPackage pkgNode) { //Sort type definitions with precedence pkgNode.typeDefinitions.sort(Comparator.comparing(t -> t.precedence)); + pkgNode.typeDefinitions = rewrite(pkgNode.typeDefinitions, env); pkgNode.xmlnsList = rewrite(pkgNode.xmlnsList, env); pkgNode.constants = rewrite(pkgNode.constants, env); pkgNode.globalVars = rewrite(pkgNode.globalVars, env); @@ -938,7 +937,7 @@ private BLangStatementExpression createIfElseFromConfigurable(BLangSimpleVariabl BLangStatementExpression stmtExpr = createStatementExpression(ifElse, resultVarRef); stmtExpr.setBType(configurableVar.getBType()); - return rewrite(stmtExpr, initFunctionEnv); + return stmtExpr; } private List getConfigurableLangLibInvocationParam(BLangSimpleVariable configurableVar) { From 8b88bd0ff94d093142fb35acf6557c2780e9ff70 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Wed, 5 Jun 2024 14:23:01 +0530 Subject: [PATCH 04/13] Add configurable test --- .../configurables/configurableProject/Config.toml | 3 +++ .../configurables/configurableProject/main/main.bal | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/Config.toml b/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/Config.toml index 075bf95a1fe1..e92807934425 100644 --- a/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/Config.toml +++ b/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/Config.toml @@ -124,3 +124,6 @@ salary = 25000.0 [[main.empInfoTab]] id = 303 name = "belle" + +[main.customConfig] +username = "chiranS" diff --git a/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/main/main.bal b/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/main/main.bal index 87112a2b585a..6ac0808381f1 100644 --- a/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/main/main.bal +++ b/tests/jballerina-integration-test/src/test/resources/configurables/configurableProject/main/main.bal @@ -83,6 +83,13 @@ type EmployeeInfo record {| float salary?; |}; +public type CustomConfiguration record { + string username; + string logLevel = "OFF"; +}; + +configurable CustomConfiguration customConfig = ?; + type UserTable table key(username); type EmployeeTable table key(id) & readonly; @@ -193,6 +200,9 @@ function testRecordValues() { test:assertEquals(34, empInfo.id); test:assertEquals("test", empInfo.name); test:assertEquals(75000.0, empInfo["salary"]); + + test:assertEquals("chiranS", customConfig.username); + test:assertEquals("OFF", customConfig.logLevel); } function testTableValues() { From 0d864be49cf1bebc2af387888f2b88088b08b9dc Mon Sep 17 00:00:00 2001 From: Thevakumar-Luheerathan Date: Wed, 19 Jun 2024 15:43:21 +0530 Subject: [PATCH 05/13] Reuse Package resolution with zero import change --- .../java/io/ballerina/projects/Package.java | 23 ++++++++- .../io/ballerina/projects/PackageContext.java | 7 +++ .../ballerina/projects/PackageResolution.java | 51 ++++++++++++++++++- .../ballerina/projects/util/ProjectUtils.java | 14 ++++- 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java index 8865d1950f7c..00b7172dad4b 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java @@ -5,6 +5,7 @@ import io.ballerina.projects.internal.DependencyManifestBuilder; import io.ballerina.projects.internal.ManifestBuilder; import io.ballerina.projects.internal.model.CompilerPluginDescriptor; +import io.ballerina.projects.util.ProjectUtils; import io.ballerina.tools.diagnostics.Diagnostic; import org.ballerinalang.model.elements.PackageID; import org.wso2.ballerinalang.compiler.PackageCache; @@ -624,13 +625,17 @@ private Map copyModules(Package oldPackage) { } private Package createNewPackage() { + Package oldPackage = this.project.currentPackage(); + PackageResolution oldResolution = oldPackage.getResolution();; PackageContext newPackageContext = new PackageContext(this.project, this.packageId, this.packageManifest, this.dependencyManifest, this.ballerinaTomlContext, this.dependenciesTomlContext, this.cloudTomlContext, this.compilerPluginTomlContext, this.balToolTomlContext, this.packageMdContext, this.compilationOptions, this.moduleContextMap, DependencyGraph.emptyGraph()); this.project.setCurrentPackage(new Package(newPackageContext, this.project)); - + if (isOldDependencyGraphValid(oldPackage, this.project.currentPackage())) { + this.project.currentPackage().packageContext().getResolution(oldResolution); + } CompilationOptions offlineCompOptions = CompilationOptions.builder().setOffline(true).build(); offlineCompOptions = offlineCompOptions.acceptTheirs(project.currentPackage().compilationOptions()); DependencyGraph newDepGraph = this.project.currentPackage().packageContext() @@ -639,6 +644,22 @@ private Package createNewPackage() { return this.project.currentPackage(); } + private static boolean isOldDependencyGraphValid(Package oldPackage, Package currentPackage) { + Set oldPackageImports = ProjectUtils.getPackageImports(oldPackage); + Set currentPackageImports = ProjectUtils.getPackageImports(currentPackage); + String oldDependencyTomlContent = oldPackage.packageContext.dependenciesTomlContext() + .map(d -> d.tomlDocument().textDocument().toString()).orElse(""); + String currentDependencyTomlContent = currentPackage.packageContext.dependenciesTomlContext() + .map(d -> d.tomlDocument().textDocument().toString()).orElse(""); + String oldBallerinaTomlContent = oldPackage.packageContext.ballerinaTomlContext() + .map(d -> d.tomlDocument().textDocument().toString()).orElse(""); + String currentBallerinaTomlContent = currentPackage.packageContext.ballerinaTomlContext() + .map(d -> d.tomlDocument().textDocument().toString()).orElse(""); + return oldPackageImports.equals(currentPackageImports) && + oldDependencyTomlContent.equals(currentDependencyTomlContent) && + oldBallerinaTomlContent.equals(currentBallerinaTomlContent); + } + private void cleanPackageCache(DependencyGraph oldGraph, DependencyGraph newGraph) { io.ballerina.projects.environment.PackageCache environmentPackageCache = diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java index 842a7a9f7ee1..643c428ccef1 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java @@ -274,6 +274,13 @@ BuildToolResolution getBuildToolResolution() { return buildToolResolution; } + PackageResolution getResolution(PackageResolution oldResolution) { + if (packageResolution == null) { + packageResolution = PackageResolution.from(oldResolution, this, this.compilationOptions); + } + return packageResolution; + } + Collection packageDependencies() { return packageDependencies; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java index 63a7d1671732..61401f13273d 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java @@ -92,7 +92,6 @@ private PackageResolution(PackageContext rootPackageContext, CompilationOptions this.blendedManifest = createBlendedManifest(rootPackageContext, projectEnvContext, this.resolutionOptions.offline()); diagnosticList.addAll(this.blendedManifest.diagnosticResult().allDiagnostics); - this.moduleResolver = createModuleResolver(rootPackageContext, projectEnvContext); this.dependencyGraph = buildDependencyGraph(); DependencyResolution dependencyResolution = new DependencyResolution( @@ -100,10 +99,60 @@ private PackageResolution(PackageContext rootPackageContext, CompilationOptions resolveDependencies(dependencyResolution); } + private PackageResolution(PackageResolution packageResolution, PackageContext rootPackageContext, + CompilationOptions compilationOptions) { + this.rootPackageContext = rootPackageContext; + this.diagnosticList = new ArrayList<>(); + this.compilationOptions = compilationOptions; + this.resolutionOptions = getResolutionOptions(rootPackageContext, compilationOptions); + ProjectEnvironment projectEnvContext = rootPackageContext.project().projectEnvironmentContext(); + this.packageResolver = projectEnvContext.getService(PackageResolver.class); + this.blendedManifest = createBlendedManifest(rootPackageContext, projectEnvContext, + this.resolutionOptions.offline()); + diagnosticList.addAll(this.blendedManifest.diagnosticResult().allDiagnostics); + this.moduleResolver = createModuleResolver(rootPackageContext, projectEnvContext); + LinkedHashSet moduleLoadRequests = getModuleLoadRequestsOfDirectDependencies(); + moduleResolver.resolveModuleLoadRequests(moduleLoadRequests); + this.dependencyGraph = cloneDependencyGraphNewRoot(packageResolution.dependencyGraph, + rootPackageContext.project().currentPackage()); + this.dependencyGraphDump = packageResolution.dependencyGraphDump; + DependencyResolution dependencyResolution = new DependencyResolution( + projectEnvContext.getService(PackageCache.class), moduleResolver, dependencyGraph); + resolveDependencies(dependencyResolution); + } + + private DependencyGraph cloneDependencyGraphNewRoot + (DependencyGraph depGraph, Package rootPackage) { + ResolvedPackageDependency oldRoot = depGraph.getRoot(); + ResolvedPackageDependency newRoot = new ResolvedPackageDependency(rootPackage, + oldRoot.scope(), oldRoot.dependencyResolvedType()); + DependencyGraphBuilder depGraphBuilder = + DependencyGraphBuilder.getBuilder(newRoot); + for (ResolvedPackageDependency depNode : depGraph.getNodes()) { + if (depNode == oldRoot) { + depGraphBuilder.add(newRoot); + } else { + depGraphBuilder.add(depNode); + } + List directPkgDependencies = + depGraph.getDirectDependencies(depNode) + .stream() + .map(directDepNode -> directDepNode == oldRoot ? newRoot : directDepNode) + .collect(Collectors.toList()); + depGraphBuilder.addDependencies(depNode, directPkgDependencies); + } + return depGraphBuilder.build(); + } + static PackageResolution from(PackageContext rootPackageContext, CompilationOptions compilationOptions) { return new PackageResolution(rootPackageContext, compilationOptions); } + static PackageResolution from(PackageResolution packageResolution, PackageContext + packageContext, CompilationOptions compilationOptions) { + return new PackageResolution(packageResolution, packageContext, compilationOptions); + } + /** * Returns the package dependency graph of this package. * diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java index 898cedddf0e7..b5df9aadbb65 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java @@ -49,6 +49,8 @@ import io.ballerina.projects.internal.model.BuildJson; import io.ballerina.projects.internal.model.Dependency; import io.ballerina.projects.internal.model.ToolDependency; +import io.ballerina.tools.diagnostics.Diagnostic; +import io.ballerina.tools.diagnostics.DiagnosticSeverity; import org.apache.commons.compress.archivers.jar.JarArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveEntryPredicate; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; @@ -197,10 +199,18 @@ public static Set getPackageImports(Package pkg) { private static void getPackageImports(Set imports, Module module, Collection documentIds) { for (DocumentId docId : documentIds) { Document document = module.document(docId); - ModulePartNode modulePartNode = document.syntaxTree().rootNode(); - for (ImportDeclarationNode importDcl : modulePartNode.imports()) { + boolean isErrorInImport = false; + for (Diagnostic diagnostic : importDcl.diagnostics()) { + if (diagnostic.diagnosticInfo().severity() == DiagnosticSeverity.ERROR) { + isErrorInImport = true; + break; + } + } + if (isErrorInImport) { + continue; + } String orgName = ""; if (importDcl.orgName().isPresent()) { orgName = importDcl.orgName().get().orgName().text(); From 2605502a81bc4cd97e6ed2731bd585d03fd89e7f Mon Sep 17 00:00:00 2001 From: dulaj Date: Fri, 7 Jun 2024 11:57:15 +0530 Subject: [PATCH 06/13] Fix getting non-accessible symbol error --- .../compiler/semantics/analyzer/Types.java | 3 +- .../intersection/IntersectionTypeTest.java | 6 +++ .../error-intersection-access/Ballerina.toml | 7 +++ .../error_intersection_access_test.bal | 43 +++++++++++++++++++ .../error_intersection_mod.bal | 33 ++++++++++++++ 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/Ballerina.toml create mode 100644 tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal create mode 100644 tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/modules/error_intersection_mod/error_intersection_mod.bal 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 d602a103edbf..3ad7f4e67044 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 @@ -5695,7 +5695,8 @@ private BErrorType createErrorType(BType lhsType, BType rhsType, BType detailTyp public BErrorType createErrorType(BType detailType, long flags, SymbolEnv env) { String name = anonymousModelHelper.getNextAnonymousIntersectionErrorTypeName(env.enclPkg.packageID); - BErrorTypeSymbol errorTypeSymbol = Symbols.createErrorSymbol(flags | Flags.ANONYMOUS, Names.fromString(name), + BErrorTypeSymbol errorTypeSymbol = Symbols.createErrorSymbol(flags | Flags.ANONYMOUS | Flags.PUBLIC, + Names.fromString(name), env.enclPkg.symbol.pkgID, null, env.scope.owner, symTable.builtinPos, VIRTUAL); errorTypeSymbol.scope = new Scope(errorTypeSymbol); diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java index 6c8a1629b734..5df620c06eb2 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java @@ -264,6 +264,12 @@ public void testUnsupportedIntersectionNegative() { assertEquals(result.getErrorCount(), index); } + @Test + public void testErrorIntersectionAccessTest() { + CompileResult result = BCompileUtil.compile("test-src/types/intersection/error-intersection-access"); + assertEquals(result.getDiagnostics().length, 0); + } + @AfterClass public void tearDown() { readOnlyIntersectionResults = null; diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/Ballerina.toml b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/Ballerina.toml new file mode 100644 index 000000000000..71d5616b4ab1 --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/Ballerina.toml @@ -0,0 +1,7 @@ +[package] +org = "testorg" +name = "error_intersection_access" +version = "0.1.0" + +[build-options] +observabilityIncluded = true diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal new file mode 100644 index 000000000000..a9ba3fe465f3 --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal @@ -0,0 +1,43 @@ +// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import error_intersection_access.error_intersection_mod as err_lib; + +function testErrorIntersectionAccessTest(int code) returns error? { + string reason = "response error"; + + if code > 500 { + return error err_lib:RemoteServerError(reason); + } + + if code == 500 { + return error err_lib:ApplicationResponseError(reason); + } + + if code > 400 { + if code == 404 { + return error err_lib:ClientRequestErrorWithStatusCode(reason, code = code); + } + + return error err_lib:ApplicationResponseErrorWithStatusCode(reason, code = code); + } + + if code == 400 { + return error err_lib:BadRequestError(reason, code = 0); + } + + return error err_lib:Error(reason); +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/modules/error_intersection_mod/error_intersection_mod.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/modules/error_intersection_mod/error_intersection_mod.bal new file mode 100644 index 000000000000..869c6bd61ea7 --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/modules/error_intersection_mod/error_intersection_mod.bal @@ -0,0 +1,33 @@ +// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +public type Status record { + int code; +}; + +public type Error distinct error; + +public type ClientRequestError distinct Error & error; + +public type RemoteServerError distinct error & error; + +public type ApplicationResponseError distinct ClientRequestError & RemoteServerError; + +public type ApplicationResponseErrorWithStatusCode distinct ApplicationResponseError & error; + +public type ClientRequestErrorWithStatusCode distinct ClientRequestError & error; + +public type BadRequestError distinct ApplicationResponseErrorWithStatusCode & ClientRequestErrorWithStatusCode; From 6420b3ed1ee37fbfd6e3e707867cdc621d83dede Mon Sep 17 00:00:00 2001 From: dulaj Date: Fri, 7 Jun 2024 12:44:34 +0530 Subject: [PATCH 07/13] Changed to errorCount() --- .../test/types/intersection/IntersectionTypeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java index 5df620c06eb2..0af630feff23 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java @@ -267,7 +267,7 @@ public void testUnsupportedIntersectionNegative() { @Test public void testErrorIntersectionAccessTest() { CompileResult result = BCompileUtil.compile("test-src/types/intersection/error-intersection-access"); - assertEquals(result.getDiagnostics().length, 0); + assertEquals(result.getErrorCount(), 0); } @AfterClass From db0b569086556549c57b3faaea93208b03cdb9c5 Mon Sep 17 00:00:00 2001 From: dulaj Date: Mon, 10 Jun 2024 09:54:42 +0530 Subject: [PATCH 08/13] Address review comments --- .../ballerinalang/compiler/semantics/analyzer/Types.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 3ad7f4e67044..24b542d353ab 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 @@ -5685,8 +5685,9 @@ private BErrorType createErrorType(BType lhsType, BType rhsType, BType detailTyp BErrorType lhsErrorType = (BErrorType) lhsType; BErrorType rhsErrorType = (BErrorType) rhsType; - BErrorType errorType = createErrorType(detailType, lhsType.flags, env); - errorType.tsymbol.flags |= rhsType.flags; + long flags = lhsType.flags | rhsType.flags | Flags.PUBLIC; // Anonymous error intersection types must be public + + BErrorType errorType = createErrorType(detailType, flags, env); errorType.typeIdSet = BTypeIdSet.getIntersection(lhsErrorType.typeIdSet, rhsErrorType.typeIdSet); @@ -5695,8 +5696,7 @@ private BErrorType createErrorType(BType lhsType, BType rhsType, BType detailTyp public BErrorType createErrorType(BType detailType, long flags, SymbolEnv env) { String name = anonymousModelHelper.getNextAnonymousIntersectionErrorTypeName(env.enclPkg.packageID); - BErrorTypeSymbol errorTypeSymbol = Symbols.createErrorSymbol(flags | Flags.ANONYMOUS | Flags.PUBLIC, - Names.fromString(name), + BErrorTypeSymbol errorTypeSymbol = Symbols.createErrorSymbol(flags | Flags.ANONYMOUS, Names.fromString(name), env.enclPkg.symbol.pkgID, null, env.scope.owner, symTable.builtinPos, VIRTUAL); errorTypeSymbol.scope = new Scope(errorTypeSymbol); From 2c64bc93ee09bf0fabfaa4bb6011811a2d3e138a Mon Sep 17 00:00:00 2001 From: NipunaMadhushan Date: Fri, 28 Jun 2024 11:50:52 +0530 Subject: [PATCH 09/13] Include response error count metric --- .../observability/metrics/BallerinaMetricsObserver.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java index 8b13a742095e..d796ed991094 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java @@ -127,6 +127,10 @@ private void stopObservation(ObserverContext observerContext) { "Total response response time for all requests", tags)).increment(duration); metricRegistry.counter(new MetricId("requests_total", "Total number of requests", tags)).increment(); + if (statusCode != null && 400 <= statusCode && statusCode < 600) { + metricRegistry.counter(new MetricId("response_errors_total", + "Total number of response errors", tags)).increment(); + } } catch (RuntimeException e) { handleError("multiple metrics", tags, e); } From 863c1dee2735080f213ef0116491d5324596b694 Mon Sep 17 00:00:00 2001 From: dulaj Date: Fri, 28 Jun 2024 14:42:33 +0530 Subject: [PATCH 10/13] Address review suggestions --- .../compiler/semantics/analyzer/Types.java | 3 +- .../error_intersection_access_test.bal | 46 ++++++++++++------- 2 files changed, 31 insertions(+), 18 deletions(-) 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 24b542d353ab..b6f80c1f19cf 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 @@ -5685,8 +5685,7 @@ private BErrorType createErrorType(BType lhsType, BType rhsType, BType detailTyp BErrorType lhsErrorType = (BErrorType) lhsType; BErrorType rhsErrorType = (BErrorType) rhsType; - long flags = lhsType.flags | rhsType.flags | Flags.PUBLIC; // Anonymous error intersection types must be public - + long flags = lhsType.flags | rhsType.flags | Flags.PUBLIC; // Anonymous (generated) types are marked as public. BErrorType errorType = createErrorType(detailType, flags, env); errorType.typeIdSet = BTypeIdSet.getIntersection(lhsErrorType.typeIdSet, rhsErrorType.typeIdSet); diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal index a9ba3fe465f3..dae071db9529 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal @@ -16,28 +16,42 @@ import error_intersection_access.error_intersection_mod as err_lib; -function testErrorIntersectionAccessTest(int code) returns error? { - string reason = "response error"; +public function testErrorIntersectionAccessTest() { + err_lib:RemoteServerError remoteServerErr = error err_lib:RemoteServerError("remote server error"); + assertEquality("remote server error", remoteServerErr.message()); - if code > 500 { - return error err_lib:RemoteServerError(reason); - } + err_lib:ApplicationResponseError applResponeErr = error err_lib:ApplicationResponseError("application response server error"); + assertEquality("application response server error", applResponeErr.message()); - if code == 500 { - return error err_lib:ApplicationResponseError(reason); - } + err_lib:ClientRequestErrorWithStatusCode clientReqErrWithStatusCode = + error err_lib:ClientRequestErrorWithStatusCode("client request error", code = 404); + assertEquality("client request error", clientReqErrWithStatusCode.message()); + assertEquality(404, clientReqErrWithStatusCode.detail().code); + + err_lib:ApplicationResponseErrorWithStatusCode applResponseErrWithStatusCode = + error err_lib:ApplicationResponseErrorWithStatusCode("application response error", code = 401); + assertEquality("application response error", applResponseErrWithStatusCode.message()); + assertEquality(401, applResponseErrWithStatusCode.detail().code); - if code > 400 { - if code == 404 { - return error err_lib:ClientRequestErrorWithStatusCode(reason, code = code); - } + err_lib:BadRequestError badReqErr = error err_lib:BadRequestError("bad request error", code = 400); + assertEquality("bad request error", badReqErr); + assertEquality(400, badReqErr.detail().code); + + err_lib:Error err = error err_lib:Error("response error"); + assertEquality("error", err.message()); +} - return error err_lib:ApplicationResponseErrorWithStatusCode(reason, code = code); +function assertEquality(any|error actual, any|error expected) { + if expected is anydata && actual is anydata && expected == actual { + return; } - if code == 400 { - return error err_lib:BadRequestError(reason, code = 0); + if expected === actual { + return; } - return error err_lib:Error(reason); + string expectedValAsString = expected is error ? expected.toString() : expected.toString(); + string actualValAsString = actual is error ? actual.toString() : actual.toString(); + panic error("AssertionError", + message = "expected '" + expectedValAsString + "', found '" + actualValAsString + "'"); } From 467451a3bb6b4b16fe6712a888a80e46b2921a4c Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Fri, 14 Jun 2024 11:29:30 +0530 Subject: [PATCH 11/13] Fix review suggestion --- .../java/org/wso2/ballerinalang/compiler/desugar/Desugar.java | 1 + 1 file changed, 1 insertion(+) 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 58650d831354..fc601e0409a7 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 @@ -937,6 +937,7 @@ private BLangStatementExpression createIfElseFromConfigurable(BLangSimpleVariabl BLangStatementExpression stmtExpr = createStatementExpression(ifElse, resultVarRef); stmtExpr.setBType(configurableVar.getBType()); + // This statement expression is desugared when visiting the init function return stmtExpr; } From 61edaee8f03ecfeee6dc3251f635fb43ba68e537 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Mon, 24 Jun 2024 10:28:31 +0530 Subject: [PATCH 12/13] Fix review suggestions --- .../java/org/wso2/ballerinalang/compiler/desugar/Desugar.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fc601e0409a7..31fc3db1cb13 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 @@ -937,7 +937,7 @@ private BLangStatementExpression createIfElseFromConfigurable(BLangSimpleVariabl BLangStatementExpression stmtExpr = createStatementExpression(ifElse, resultVarRef); stmtExpr.setBType(configurableVar.getBType()); - // This statement expression is desugared when visiting the init function + // This statement expression is desugared when it is visited in the init function return stmtExpr; } From 6eed512cc5f1deefcd6b4e8f1597d190f8b14f99 Mon Sep 17 00:00:00 2001 From: dulaj Date: Mon, 1 Jul 2024 13:55:42 +0530 Subject: [PATCH 13/13] Update test --- .../intersection/IntersectionTypeTest.java | 1 + .../error_intersection_access_test.bal | 53 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java index 0af630feff23..93d7588fe1f7 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/intersection/IntersectionTypeTest.java @@ -268,6 +268,7 @@ public void testUnsupportedIntersectionNegative() { public void testErrorIntersectionAccessTest() { CompileResult result = BCompileUtil.compile("test-src/types/intersection/error-intersection-access"); assertEquals(result.getErrorCount(), 0); + BRunUtil.invoke(result, "testErrorIntersectionFromImportedModule"); } @AfterClass diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal index dae071db9529..0f49c8555bd3 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/intersection/error-intersection-access/error_intersection_access_test.bal @@ -16,42 +16,41 @@ import error_intersection_access.error_intersection_mod as err_lib; -public function testErrorIntersectionAccessTest() { - err_lib:RemoteServerError remoteServerErr = error err_lib:RemoteServerError("remote server error"); - assertEquality("remote server error", remoteServerErr.message()); +const MESSAGE = "Message"; - err_lib:ApplicationResponseError applResponeErr = error err_lib:ApplicationResponseError("application response server error"); - assertEquality("application response server error", applResponeErr.message()); +public function testErrorIntersectionFromImportedModule() { + err_lib:RemoteServerError remoteServerErr = error err_lib:RemoteServerError(MESSAGE); + assertError(remoteServerErr); - err_lib:ClientRequestErrorWithStatusCode clientReqErrWithStatusCode = - error err_lib:ClientRequestErrorWithStatusCode("client request error", code = 404); - assertEquality("client request error", clientReqErrWithStatusCode.message()); - assertEquality(404, clientReqErrWithStatusCode.detail().code); + err_lib:ApplicationResponseError applResponeErr = error err_lib:ApplicationResponseError(MESSAGE); + assertError(applResponeErr); - err_lib:ApplicationResponseErrorWithStatusCode applResponseErrWithStatusCode = - error err_lib:ApplicationResponseErrorWithStatusCode("application response error", code = 401); - assertEquality("application response error", applResponseErrWithStatusCode.message()); - assertEquality(401, applResponseErrWithStatusCode.detail().code); + err_lib:ClientRequestErrorWithStatusCode clientReqErrWithStatusCode = error (MESSAGE, code = 404); + assertError(clientReqErrWithStatusCode, 404); - err_lib:BadRequestError badReqErr = error err_lib:BadRequestError("bad request error", code = 400); - assertEquality("bad request error", badReqErr); - assertEquality(400, badReqErr.detail().code); + err_lib:ApplicationResponseErrorWithStatusCode appRespErrWithStatusCode = error (MESSAGE, code = 401); + assertError(appRespErrWithStatusCode, 401); - err_lib:Error err = error err_lib:Error("response error"); - assertEquality("error", err.message()); + err_lib:BadRequestError badReqErr = error err_lib:BadRequestError(MESSAGE, code = 400); + assertError(badReqErr, 400); + + err_lib:Error err = error err_lib:Error(MESSAGE); + assertError(err); } -function assertEquality(any|error actual, any|error expected) { - if expected is anydata && actual is anydata && expected == actual { - return; +function assertError(any|error actual, int? code = ()) { + if actual !is error { + panic error(string `expected an error, found '${actual.toString()}'`); } - if expected === actual { - return; + if MESSAGE != actual.message() { + panic error(string `expected message: '${MESSAGE}', found: '${actual.message()}'`); } - string expectedValAsString = expected is error ? expected.toString() : expected.toString(); - string actualValAsString = actual is error ? actual.toString() : actual.toString(); - panic error("AssertionError", - message = "expected '" + expectedValAsString + "', found '" + actualValAsString + "'"); + if code != () { + var detail = actual.detail(); + if code != detail.code { + panic error(string `expected code: '${code}', found: '${detail.code}'`); + } + } }