ballerina-lang
ballerina-lang copied to clipboard
[Bug]: An invalid error is generated when using a constant expression in a spread operator
Description
The error expression is not a constant expression (BCE3504) is generated for the following code when using a constant array within a spread operator for the context of assigning a value for a table key that requires a constant expression.
The error is generated by the DataflowAnalyzer because it does not consider the LIST_CONSTRUCTOR_SPREAD_OP when generating the hash.
https://github.com/ballerina-platform/ballerina-lang/blob/e38dc2bccbfb9aca9593d6951a181acce3968bed/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java#L1445
Steps to Reproduce
Execute the following Ballerina code.
type Row record {|
readonly int[] k;
int value;
|};
const int[] INT_ARR = [1, 2];
public function main() {
table<Row> key (k) t = table [
{k: [1, 3, ...INT_ARR], value: 0}
];
_ = t.count();
}
Affected Version(s)
Ballerina 2201.8.4 (Swan Lake Update 8)
OS, DB, other environment details and versions
OS: macOS 14.2.1 23C71 JDK: openjdk 17.0.8 2023-07-18
Related area
-> Compilation
Related issue(s) (optional)
No response
Suggested label(s) (optional)
No response
Suggested assignee(s) (optional)
No response
The similar concern occurs when using the record field spread operator as well. Consider the following example:
type Row6 record {
readonly map<anydata> k;
int value;
};
const map<anydata> MAP_VAL = {"X": 12, "Y": 22};
function testMappingConstructorExprAsKeyValue() {
table<Row6> key(k) tbl = table [
{k: {"A": "a", ...MAP_VAL, "C": [13.5, 24.3]}, value: 17}
];
}
In the DataflowAnalyzer, We can use node.getPosition() instead of casting it to ExpressionNode, as the compiler crashes for the above example.
https://github.com/ballerina-platform/ballerina-lang/blob/e38dc2bccbfb9aca9593d6951a181acce3968bed/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java#L1445
The following crash report is generated:
[2024-03-22 09:21:09,399] SEVERE {b7a.log.crash} - class org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral$BLangRecordSpreadOperatorField cannot be cast to class org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression (org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral$BLangRecordSpreadOperatorField and org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression are in unnamed module of loader 'app')
java.lang.ClassCastException: class org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral$BLangRecordSpreadOperatorField cannot be cast to class org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression (org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral$BLangRecordSpreadOperatorField and org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression are in unnamed module of loader 'app')
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.hash(DataflowAnalyzer.java:1445)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.hash(DataflowAnalyzer.java:1340)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.generateHash(DataflowAnalyzer.java:1148)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.checkForDuplicateKeys(DataflowAnalyzer.java:1121)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.visit(DataflowAnalyzer.java:1111)
at org.wso2.ballerinalang.compiler.tree.expressions.BLangTableConstructorExpr.accept(BLangTableConstructorExpr.java:70)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyzeNode(DataflowAnalyzer.java:2528)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.visit(DataflowAnalyzer.java:690)
at org.wso2.ballerinalang.compiler.tree.BLangSimpleVariable.accept(BLangSimpleVariable.java:54)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyzeNode(DataflowAnalyzer.java:2528)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.visit(DataflowAnalyzer.java:653)
at org.wso2.ballerinalang.compiler.tree.statements.BLangSimpleVariableDef.accept(BLangSimpleVariableDef.java:50)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyzeNode(DataflowAnalyzer.java:2528)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.visit(DataflowAnalyzer.java:472)
at org.wso2.ballerinalang.compiler.tree.BLangBlockFunctionBody.accept(BLangBlockFunctionBody.java:60)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyzeNode(DataflowAnalyzer.java:2528)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyzeBranch(DataflowAnalyzer.java:2496)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.visit(DataflowAnalyzer.java:429)
at org.wso2.ballerinalang.compiler.tree.BLangFunction.accept(BLangFunction.java:76)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyzeNode(DataflowAnalyzer.java:2528)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.visit(DataflowAnalyzer.java:344)
at org.wso2.ballerinalang.compiler.tree.BLangPackage.accept(BLangPackage.java:167)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyzeNode(DataflowAnalyzer.java:2528)
at org.wso2.ballerinalang.compiler.semantics.analyzer.DataflowAnalyzer.analyze(DataflowAnalyzer.java:314)
at io.ballerina.projects.internal.CompilerPhaseRunner.dataflowAnalyze(CompilerPhaseRunner.java:196)
at io.ballerina.projects.internal.CompilerPhaseRunner.performTypeCheckPhases(CompilerPhaseRunner.java:120)
at io.ballerina.projects.ModuleContext.compileInternal(ModuleContext.java:435)
at io.ballerina.projects.ModuleCompilationState$1.compile(ModuleCompilationState.java:45)
at io.ballerina.projects.ModuleContext.compile(ModuleContext.java:383)
at io.ballerina.projects.PackageCompilation.compileModulesInternal(PackageCompilation.java:208)
at io.ballerina.projects.PackageCompilation.compileModules(PackageCompilation.java:192)
at io.ballerina.projects.PackageCompilation.compile(PackageCompilation.java:99)
at io.ballerina.projects.PackageCompilation.from(PackageCompilation.java:94)
at io.ballerina.projects.PackageContext.getPackageCompilation(PackageContext.java:242)
at io.ballerina.projects.Package.getCompilation(Package.java:150)
at io.ballerina.projects.Package.runCodeGeneratorPlugins(Package.java:319)
at io.ballerina.cli.task.CompileTask.execute(CompileTask.java:142)
at io.ballerina.cli.TaskExecutor.executeTasks(TaskExecutor.java:40)
at io.ballerina.cli.cmd.RunCommand.execute(RunCommand.java:223)
at java.base/java.util.Optional.ifPresent(Optional.java:178)
at io.ballerina.cli.launcher.Main.main(Main.java:58)
ERROR [.:(1:1,1:1)] Compilation failed due to: class org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral$BLangRecordSpreadOperatorField cannot be cast to class org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression (org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral$BLangRecordSpreadOperatorField and org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression are in unnamed module of loader 'app')
error: compilation contains errors