janino-compiler/janino

Some expressions are failing without explicit cast of null

snuyanzin opened this issue · 11 comments

After update to Calcite 1.28 (janino 3.1.6) there is a failure (also reproducible with 3.1.8).
It complains for these lines from generated code

/* 91 */          externalResult$104343 = (java.lang.String) function_org$apache$flink$table$planner$runtime$stream$sql$FunctionITCase$ClassNameScalarFunction
/* 92 */            .eval(true ? null : ((java.lang.String) converter$104341.toExternal((org.apache.flink.table.data.binary.BinaryStringData) ((org.apache.flink.table.data.binary.BinaryStringData) org.apache.flink.table.data.binary.BinaryStringData.EMPTY_UTF8))));

The interesting thing is that if I put explicit cast of null to the expected type then the issue is disappeared.

the full stacktrace is

Caused by: org.codehaus.commons.compiler.InternalCompilerException: Compiling "ExpressionReducer$104353" in Line 5, Column 14: Line 43, Column 23: Compiling "map(Object _in1)"
	at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:402)
	at org.codehaus.janino.UnitCompiler.access$000(UnitCompiler.java:236)
	at org.codehaus.janino.UnitCompiler$2.visitCompilationUnit(UnitCompiler.java:363)
	at org.codehaus.janino.UnitCompiler$2.visitCompilationUnit(UnitCompiler.java:361)
	at org.codehaus.janino.Java$CompilationUnit.accept(Java.java:371)
	at org.codehaus.janino.UnitCompiler.compileUnit(UnitCompiler.java:361)
	at org.codehaus.janino.SimpleCompiler.cook(SimpleCompiler.java:264)
	at org.codehaus.janino.SimpleCompiler.compileToClassLoader(SimpleCompiler.java:517)
	at org.codehaus.janino.SimpleCompiler.cook(SimpleCompiler.java:241)
	at org.codehaus.janino.SimpleCompiler.cook(SimpleCompiler.java:219)
	at org.codehaus.commons.compiler.Cookable.cook(Cookable.java:82)
	at org.codehaus.commons.compiler.Cookable.cook(Cookable.java:77)
	at org.apache.flink.table.runtime.generated.CompileUtils.doCompile(CompileUtils.java:104)
	... 100 more
Caused by: org.codehaus.commons.compiler.InternalCompilerException: Line 43, Column 23: Compiling "map(Object _in1)"
	at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:3296)
	at org.codehaus.janino.UnitCompiler.compileDeclaredMethods(UnitCompiler.java:1430)
	at org.codehaus.janino.UnitCompiler.compileDeclaredMethods(UnitCompiler.java:1403)
	at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:829)
	at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:442)
	at org.codehaus.janino.UnitCompiler.access$400(UnitCompiler.java:236)
	at org.codehaus.janino.UnitCompiler$3.visitPackageMemberClassDeclaration(UnitCompiler.java:422)
	at org.codehaus.janino.UnitCompiler$3.visitPackageMemberClassDeclaration(UnitCompiler.java:418)
	at org.codehaus.janino.Java$PackageMemberClassDeclaration.accept(Java.java:1688)
	at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:418)
	at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:392)
	... 112 more

Caused by: org.codehaus.commons.compiler.InternalCompilerException: Line 91, Column 11
	at org.codehaus.janino.UnitCompiler.compileStatements(UnitCompiler.java:1648)
	at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:3621)
	at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:3292)
	... 122 more
Caused by: java.lang.AssertionError: null
	at org.codehaus.janino.CodeContext.popObjectOrUninitializedOrUninitializedThisOperand(CodeContext.java:1602)
	at org.codehaus.janino.CodeContext.popOperandAssignableTo(CodeContext.java:1538)
	at org.codehaus.janino.UnitCompiler.invoke(UnitCompiler.java:12417)
	at org.codehaus.janino.UnitCompiler.invokeMethod(UnitCompiler.java:13101)
	at org.codehaus.janino.UnitCompiler.compileGet2(UnitCompiler.java:5351)
	at org.codehaus.janino.UnitCompiler.access$9300(UnitCompiler.java:236)
	at org.codehaus.janino.UnitCompiler$16.visitMethodInvocation(UnitCompiler.java:4698)
	at org.codehaus.janino.UnitCompiler$16.visitMethodInvocation(UnitCompiler.java:4674)
	at org.codehaus.janino.Java$MethodInvocation.accept(Java.java:5470)
	at org.codehaus.janino.UnitCompiler.compileGet(UnitCompiler.java:4674)
	at org.codehaus.janino.UnitCompiler.compileGetValue(UnitCompiler.java:5817)
	at org.codehaus.janino.UnitCompiler.compileGet2(UnitCompiler.java:5161)
	at org.codehaus.janino.UnitCompiler.access$8800(UnitCompiler.java:236)
	at org.codehaus.janino.UnitCompiler$16.visitCast(UnitCompiler.java:4693)
	at org.codehaus.janino.UnitCompiler$16.visitCast(UnitCompiler.java:4674)
	at org.codehaus.janino.Java$Cast.accept(Java.java:5283)
	at org.codehaus.janino.UnitCompiler.compileGet(UnitCompiler.java:4674)
	at org.codehaus.janino.UnitCompiler.compileGetValue(UnitCompiler.java:5817)
	at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:4064)
	at org.codehaus.janino.UnitCompiler.access$6300(UnitCompiler.java:236)
	at org.codehaus.janino.UnitCompiler$13.visitAssignment(UnitCompiler.java:4020)
	at org.codehaus.janino.UnitCompiler$13.visitAssignment(UnitCompiler.java:4003)
	at org.codehaus.janino.Java$Assignment.accept(Java.java:4864)
	at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:4003)
	at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:2487)
	at org.codehaus.janino.UnitCompiler.access$1800(UnitCompiler.java:236)
	at org.codehaus.janino.UnitCompiler$6.visitExpressionStatement(UnitCompiler.java:1563)
	at org.codehaus.janino.UnitCompiler$6.visitExpressionStatement(UnitCompiler.java:1558)
	at org.codehaus.janino.Java$ExpressionStatement.accept(Java.java:3209)
	at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:1558)
	at org.codehaus.janino.UnitCompiler.compileStatements(UnitCompiler.java:1644)
	... 124 more

Reproduces with

Object o = true ? null : "";

See org.codehaus.commons.compiler.tests.ReportedBugsTest.testIssue188().

Fixed it... please test!

amazing, thank you
will have a look soon

Flink tests are still failing with this issue.
It looks like it is fixed for Object o = true ? null : "";

However it is still reproducible when this expression is a passing arg like

String s1 = new StringBuilder().append(true ? (String) null : "abc").toString(); // ok
String s2 = new StringBuilder().append(true ? null : "abc").toString(); // <= InternalCompilerException

Sigh... I’ll look into it.

Hi @aunkrig
I just want to share some findings regarding this issue.
After some debugging I realized that
such condition

if (cv == null && rv instanceof ConditionalExpression) {
    this.tryNullConversion(IClass.NULL, this.getType2((ConditionalExpression)rv));
}

in org.codehaus.janino.UnitCompiler#compileGetValue(org.codehaus.janino.Java.Rvalue) helps to pass tests.
Also there is a commit in my fork, where changes could be seen snuyanzin@2dff5b4

WDYT how bad/good is this approach?

I fixed it differently... please test.

It behaves a bit strange.

From one side mvn clean verify for janino-parent fails with

Tests in error: 
  ReportedBugsTest.testIssue188:1662->CommonsCompilerTestSuite.assertScriptExecutable:215 » Compile

on lines

this.assertScriptExecutable("String s1 = new StringBuilder().append(true ? (String) null : \"abc\").toString(); // ok");
this.assertScriptExecutable("String s2 = new StringBuilder().append(true ? null : \"abc\").toString(); // <= InternalCompilerException");

At the same time now it passes Flink tests...

Strange... in my development environment, a different test fails now:
org.codehaus.commons.compiler.tests.JlsTest.test_9_3_1__Initialization_of_Fields_in_Interfaces__2(JlsTest.java:802)
this.assertClassBodyUncookable("public final static float x = 0D;");
fails with the JDK (not the Janino!) implementation with JRE 8:
Line 1, Column 31: incompatible types: possible lossy conversion from double to float (compiler.err.prob.found.req)
The reason being is that the compile error handling of the JDK implementation chokes on the first compilation error:
The reason appears to be that org.codehaus.commons.compiler.jdk.Compiler.compile(...).new DiagnosticListener() {...}.report(Diagnostic<? extends JavaFileObject>) (Line 350) attempts to "tunnel" the compilation error through the JDK compiler via a RuntimeException, and that doesn't work (at least with JDK 8), because com.sun.tools.javac.code.Symbol.VarSymbol.getConstValue() catches Exception and throws an AssertionError.

But now let's turn to testIssue188().

Ah, found the reason for the testIssue188() test error:
JAVAC does not like source code that ends with a C++-style comment and no line terminator.

Change test case accordingly.

Please test.

checked locally
now both Janino and Flink tests are passing