ballerina-lang icon indicating copy to clipboard operation
ballerina-lang copied to clipboard

[Bug]: An invalid error is generated when using a constant expression in a spread operator

Open nipunayf opened this issue 1 year ago • 1 comments

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

nipunayf avatar Jan 16 '24 05:01 nipunayf

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

nipunayf avatar Jan 17 '24 08:01 nipunayf