gwtproject / gwt

GWT Open Source Project
http://www.gwtproject.org
1.53k stars 377 forks source link

GWT cannot optimize switched expressions #10005

Closed natros closed 1 month ago

natros commented 1 month ago

GWT version: HEAD-SNAPSHOT Java Version: 17


Description

For some reason GWT cannot compile the following code

Steps to reproduce
public class Basic implements EntryPoint {
  @Override
  public void onModuleLoad() {
    getKind(Kind.A);
  }

  private static String getKind(Kind kind) {
    return switch (kind) {
      case A -> "1";
      case B -> "2";
      case C -> "3";
      case D -> "4";
      case E -> "5";
      case F -> "6";
      case G -> "7";
      case H -> "8";
      case I -> "9";
      case J -> "10";
      case K -> "11";
      case L -> "12";
      case M -> "13";
      case N -> "14";
      case O -> "15";
    };
  }
}
Output
Compiling module it.pkg.Basic
   Compiling 2 permutations
      Compiling permutation 0...
      [ERROR] An internal compiler exception occurred
com.google.gwt.dev.jjs.InternalCompilerException: Unexpected error during visit.
    at com.google.gwt.dev.jjs.ast.JVisitor.translateException(JVisitor.java:111)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:130)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:122)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:118)
    at com.google.gwt.dev.jjs.impl.CloneExpressionVisitor.cloneExpression(CloneExpressionVisitor.java:78)
    at com.google.gwt.dev.jjs.impl.MethodInliner$InliningVisitor.extractExpressionsFromBody(MethodInliner.java:265)
    at com.google.gwt.dev.jjs.impl.MethodInliner$InliningVisitor.tryInlineMethodCall(MethodInliner.java:147)
    at com.google.gwt.dev.jjs.impl.MethodInliner$InliningVisitor.endVisit(MethodInliner.java:112)
    at com.google.gwt.dev.jjs.ast.JMethodCall.traverse(JMethodCall.java:268)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:118)
    at com.google.gwt.dev.jjs.ast.JExpressionStatement.traverse(JExpressionStatement.java:42)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:88)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:331)
    at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:94)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:139)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:135)
    at com.google.gwt.dev.jjs.ast.JMethodBody.traverse(JMethodBody.java:83)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JMethod.visitChildren(JMethod.java:786)
    at com.google.gwt.dev.jjs.ast.JMethod.traverse(JMethod.java:778)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.impl.FullOptimizerContext.traverse(FullOptimizerContext.java:224)
    at com.google.gwt.dev.jjs.impl.MethodInliner.execImpl(MethodInliner.java:611)
    at com.google.gwt.dev.jjs.impl.MethodInliner.exec(MethodInliner.java:588)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaOneTime(JavaToJavaScriptCompiler.java:1514)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaToFixedPoint(JavaToJavaScriptCompiler.java:1443)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJava(JavaToJavaScriptCompiler.java:525)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:362)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
    at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
    at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
    at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
    at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.UnsupportedOperationException: switch expression cannot be cloned
    at com.google.gwt.dev.jjs.impl.CloneExpressionVisitor.visit(CloneExpressionVisitor.java:261)
    at com.google.gwt.dev.jjs.ast.JSwitchExpression.traverse(JSwitchExpression.java:50)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:127)
    ... 40 more
         [ERROR] at Basic.java(12): switch (Enum.$ordinal(kind))  {
  case Enum.$ordinal(Kind.A):
  yield  "1";
  case Enum.$ordinal(Kind.B):
  yield  "2";
  case Enum.$ordinal(Kind.C):
  yield  "3";
  case Enum.$ordinal(Kind.D):
  yield  "4";
  case Enum.$ordinal(Kind.E):
  yield  "5";
  case Enum.$ordinal(Kind.F):
  yield  "6";
  case Enum.$ordinal(Kind.G):
  yield  "7";
  case Enum.$ordinal(Kind.H):
  yield  "8";
  case Enum.$ordinal(Kind.I):
  yield  "9";
  case Enum.$ordinal(Kind.J):
  yield  "10";
  case Enum.$ordinal(Kind.K):
  yield  "11";
  case Enum.$ordinal(Kind.L):
  yield  "12";
  case Enum.$ordinal(Kind.M):
  yield  "13";
  case Enum.$ordinal(Kind.N):
  yield  "14";
  case Enum.$ordinal(Kind.O):
  yield  "15";
}
            com.google.gwt.dev.jjs.ast.JSwitchExpression
         [ERROR] at Basic.java(8): Basic.getKind(Kind.A)
            com.google.gwt.dev.jjs.ast.JMethodCall
         [ERROR] at Basic.java(8): Basic.getKind(Kind.A)
            com.google.gwt.dev.jjs.ast.JExpressionStatement
         [ERROR] at Basic.java(7): {
  Basic.getKind(Kind.A);
}
            com.google.gwt.dev.jjs.ast.JBlock
         [ERROR] at Basic.java(7): {
  Basic.getKind(Kind.A);
}
            com.google.gwt.dev.jjs.ast.JMethodBody
         [ERROR] at Basic.java(7): it.pkg.client.Basic.onModuleLoad()V
            com.google.gwt.dev.jjs.ast.JMethod
      [ERROR] Unrecoverable exception, shutting down
com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
    at com.google.gwt.dev.javac.CompilationProblemReporter.logAndTranslateException(CompilationProblemReporter.java:106)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:461)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
    at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
    at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
    at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
    at java.base/java.lang.Thread.run(Thread.java:840)
      [ERROR] Not all permutation were compiled , completed (0/2)
Known workarounds

-optimize=0

jnehlmeier commented 1 month ago

You should be able to forbid inlining the method in question using javaemul.internal.annotations.DoNotInline annotation as a workaround and still use a higher optimize level.

natros commented 1 month ago

Hi @niloc132

It's failing for this case

return switch (kind) {
      case A -> "1";
      case B, C, D, E, F -> "2";
      case G -> "7";
      case H -> "8";
      case I -> "9";
      case J -> "10";
      case K -> "11";
      case L -> "12";
      case M -> "13";
      case N -> "14";
      case O -> "15";
    };

with

   Compiling 2 permutations
      Compiling permutation 0...
      [ERROR] An internal compiler exception occurred
com.google.gwt.dev.jjs.InternalCompilerException: Unexpected error during visit.
    at com.google.gwt.dev.jjs.ast.JVisitor.translateException(JVisitor.java:111)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptImmutable(JModVisitor.java:313)
    at com.google.gwt.dev.jjs.ast.JCaseStatement.traverse(JCaseStatement.java:72)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:88)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:331)
    at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:94)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:139)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:135)
    at com.google.gwt.dev.jjs.ast.JSwitchExpression.traverse(JSwitchExpression.java:52)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:118)
    at com.google.gwt.dev.jjs.ast.JReturnStatement.traverse(JReturnStatement.java:40)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:88)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:331)
    at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:94)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:139)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:135)
    at com.google.gwt.dev.jjs.ast.JMethodBody.traverse(JMethodBody.java:83)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JMethod.visitChildren(JMethod.java:786)
    at com.google.gwt.dev.jjs.ast.JMethod.traverse(JMethod.java:778)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContextImmutable.traverse(JModVisitor.java:169)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemoveImmutable(JModVisitor.java:336)
    at com.google.gwt.dev.jjs.ast.JClassType.traverse(JClassType.java:147)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JProgram.visitModuleTypes(JProgram.java:1285)
    at com.google.gwt.dev.jjs.ast.JProgram.traverse(JProgram.java:1249)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.impl.MakeCallsStatic.execImpl(MakeCallsStatic.java:504)
    at com.google.gwt.dev.jjs.impl.MakeCallsStatic.exec(MakeCallsStatic.java:449)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaOneTime(JavaToJavaScriptCompiler.java:1507)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaToFixedPoint(JavaToJavaScriptCompiler.java:1443)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJava(JavaToJavaScriptCompiler.java:525)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:362)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
    at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
    at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
    at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
    at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.UnsupportedOperationException
    at java.base/java.util.Collections$UnmodifiableList.set(Collections.java:1503)
    at com.google.gwt.dev.util.collect.Lists.set(Lists.java:238)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptImmutable(JModVisitor.java:307)
    ... 49 more
         [ERROR] at Main.java(15): Enum.$ordinal(Main$Kind.B)
            com.google.gwt.dev.jjs.ast.JMethodCall
         [ERROR] at Main.java(15): case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
            com.google.gwt.dev.jjs.ast.JCaseStatement
         [ERROR] at Main.java(13): {
  case Enum.$ordinal(Main$Kind.A): 
  yield  "1";
  case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
  yield  "2";
  case Main$Kind.G.ordinal(): 
  yield  "7";
  case Main$Kind.H.ordinal(): 
  yield  "8";
  case Main$Kind.I.ordinal(): 
  yield  "9";
  case Main$Kind.J.ordinal(): 
  yield  "10";
  case Main$Kind.K.ordinal(): 
  yield  "11";
  case Main$Kind.L.ordinal(): 
  yield  "12";
  case Main$Kind.M.ordinal(): 
  yield  "13";
  case Main$Kind.N.ordinal(): 
  yield  "14";
  case Main$Kind.O.ordinal(): 
  yield  "15";
}
            com.google.gwt.dev.jjs.ast.JBlock
         [ERROR] at Main.java(13): switch (Enum.$ordinal(kind))  {
  case Enum.$ordinal(Main$Kind.A): 
  yield  "1";
  case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
  yield  "2";
  case Main$Kind.G.ordinal(): 
  yield  "7";
  case Main$Kind.H.ordinal(): 
  yield  "8";
  case Main$Kind.I.ordinal(): 
  yield  "9";
  case Main$Kind.J.ordinal(): 
  yield  "10";
  case Main$Kind.K.ordinal(): 
  yield  "11";
  case Main$Kind.L.ordinal(): 
  yield  "12";
  case Main$Kind.M.ordinal(): 
  yield  "13";
  case Main$Kind.N.ordinal(): 
  yield  "14";
  case Main$Kind.O.ordinal(): 
  yield  "15";
}
            com.google.gwt.dev.jjs.ast.JSwitchExpression
         [ERROR] at Main.java(13): return switch (Enum.$ordinal(kind))  {
  case Enum.$ordinal(Main$Kind.A): 
  yield  "1";
  case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
  yield  "2";
  case Main$Kind.G.ordinal(): 
  yield  "7";
  case Main$Kind.H.ordinal(): 
  yield  "8";
  case Main$Kind.I.ordinal(): 
  yield  "9";
  case Main$Kind.J.ordinal(): 
  yield  "10";
  case Main$Kind.K.ordinal(): 
  yield  "11";
  case Main$Kind.L.ordinal(): 
  yield  "12";
  case Main$Kind.M.ordinal(): 
  yield  "13";
  case Main$Kind.N.ordinal(): 
  yield  "14";
  case Main$Kind.O.ordinal(): 
  yield  "15";
}
            com.google.gwt.dev.jjs.ast.JReturnStatement
         [ERROR] at Main.java(12): {
  return switch (Enum.$ordinal(kind))  {
    case Enum.$ordinal(Main$Kind.A): 
    yield  "1";
    case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
    yield  "2";
    case Main$Kind.G.ordinal(): 
    yield  "7";
    case Main$Kind.H.ordinal(): 
    yield  "8";
    case Main$Kind.I.ordinal(): 
    yield  "9";
    case Main$Kind.J.ordinal(): 
    yield  "10";
    case Main$Kind.K.ordinal(): 
    yield  "11";
    case Main$Kind.L.ordinal(): 
    yield  "12";
    case Main$Kind.M.ordinal(): 
    yield  "13";
    case Main$Kind.N.ordinal(): 
    yield  "14";
    case Main$Kind.O.ordinal(): 
    yield  "15";
  }
}
            com.google.gwt.dev.jjs.ast.JBlock
         [ERROR] at Main.java(12): {
  return switch (Enum.$ordinal(kind))  {
    case Enum.$ordinal(Main$Kind.A): 
    yield  "1";
    case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
    yield  "2";
    case Main$Kind.G.ordinal(): 
    yield  "7";
    case Main$Kind.H.ordinal(): 
    yield  "8";
    case Main$Kind.I.ordinal(): 
    yield  "9";
    case Main$Kind.J.ordinal(): 
    yield  "10";
    case Main$Kind.K.ordinal(): 
    yield  "11";
    case Main$Kind.L.ordinal(): 
    yield  "12";
    case Main$Kind.M.ordinal(): 
    yield  "13";
    case Main$Kind.N.ordinal(): 
    yield  "14";
    case Main$Kind.O.ordinal(): 
    yield  "15";
  }
}
            com.google.gwt.dev.jjs.ast.JMethodBody
         [ERROR] at Main.java(12): pt.ipb.candidaturas.alunos.client.Main.getKind(Lpt/ipb/candidaturas/alunos/client/Main$Kind;)Ljava/lang/String;
            com.google.gwt.dev.jjs.ast.JMethod
         [ERROR] at Main.java(5): pt.ipb.candidaturas.alunos.client.Main (extends Object implements EntryPoint)
            com.google.gwt.dev.jjs.ast.JClassType
         [ERROR] at Unknown(0): <JProgram>
            com.google.gwt.dev.jjs.ast.JProgram
      [ERROR] Unrecoverable exception, shutting down
com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
    at com.google.gwt.dev.javac.CompilationProblemReporter.logAndTranslateException(CompilationProblemReporter.java:106)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:461)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
    at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
    at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
    at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
    at java.base/java.lang.Thread.run(Thread.java:1583)
      [ERROR] Not all permutation were compiled , completed (0/2)
alesp commented 1 month ago

Another failing example:

    @Override
    public void onModuleLoad() {
        CellTable<String> cellTable = new CellTable<>();
        cellTable.setRowStyles((row, rowIndex) -> {
            if (Math.random() > .5)
                return "a";
            return switch (rowIndex) {
                case 2 -> "b";
                case 4 -> "c";
                case 5 -> "d";
                case 6 -> "e";
                default -> null;
            };
        });
    }

The error:

[INFO]       [ERROR] An internal compiler exception occurred
[INFO] com.google.gwt.dev.jjs.InternalCompilerException: Unexpected error during visit.
[INFO]  at com.google.gwt.dev.jjs.ast.JVisitor.translateException(JVisitor.java:111)
[INFO]  at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:276)
[INFO]  at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
[INFO]  at com.google.gwt.dev.jjs.impl.FullOptimizerContext.traverse(FullOptimizerContext.java:224)
[INFO]  at com.google.gwt.dev.jjs.impl.TypeTightener.execImpl(TypeTightener.java:842)
[INFO]  at com.google.gwt.dev.jjs.impl.TypeTightener.exec(TypeTightener.java:727)
[INFO]  at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaOneTime(JavaToJavaScriptCompiler.java:1509)
[INFO]  at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaToFixedPoint(JavaToJavaScriptCompiler.java:1443)
[INFO]  at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJava(JavaToJavaScriptCompiler.java:525)
[INFO]  at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:362)
[INFO]  at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
[INFO]  at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
[INFO]  at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
[INFO]  at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO] Caused by: java.lang.NullPointerException: Cannot invoke "com.google.gwt.dev.jjs.ast.JReferenceType.isNullType()" because "thatType" is null
[INFO]  at com.google.gwt.dev.jjs.ast.JProgram.strengthenType(JProgram.java:514)
[INFO]  at com.google.gwt.dev.jjs.impl.TypeTightener.strongerType(TypeTightener.java:928)
[INFO]  at com.google.gwt.dev.jjs.impl.TypeTightener.access$1000(TypeTightener.java:128)
[INFO]  at com.google.gwt.dev.jjs.impl.TypeTightener$TightenTypesVisitor.exit(TypeTightener.java:534)
[INFO]  at com.google.gwt.dev.jjs.impl.JChangeTrackingVisitor.endVisit(JChangeTrackingVisitor.java:84)
[INFO]  at com.google.gwt.dev.jjs.ast.JMethod.traverse(JMethod.java:780)
[INFO]  at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
[INFO]  at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
[INFO]  ... 13 more
[INFO]          [ERROR] at Test.java(47): com.test.client.Test.lambda$0(Ljava/lang/String;I)Ljava/lang/String;
[INFO]             com.google.gwt.dev.jjs.ast.JMethod
[INFO]       [ERROR] Unrecoverable exception, shutting down
[INFO] com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
[INFO]  at com.google.gwt.dev.javac.CompilationProblemReporter.logAndTranslateException(CompilationProblemReporter.java:106)
[INFO]  at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:461)
[INFO]  at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
[INFO]  at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
[INFO]  at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
[INFO]  at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO]       [ERROR] Not all permutation were compiled , completed (0/2)
jnehlmeier commented 1 month ago

Interesting. The changes to JCaseStatement use immutable collections and I thought that acceptImmutable exists to handle immutable lists. But it seems like the implementations of accept(List) and acceptImmutable(List) in JModVisitor both modify the list, if the list contains more than one item. If the list contains only a single item then acceptImmutable(List) returns a new Collections.singletonList() while accept(List) edits the list in-place.

niloc132 commented 1 month ago

Wow that's irritating. Thanks @jnehlmeier for spotting that issue that my patch introduced, and @natros and @alesp for testing out the latest snapshot.

JMethod/JMethodBody/JMethodCall use this immutable pattern, it appeared to be a safer way to expand this node type so that it could have multiple children instead of just one. I'm guessing that those implementations get away with it because methods aren't modified in this way, but entirely replaced, but other existing optimizations assume they can mutate anything. In this case, I think this is the Kind.ordinal() method being made static, inside each case statement.

I'll get this figured out tomorrow, thanks again for the continued testing. @natros and @alesp are you building from a SDK zip, or using maven? In either case, can I get you a build before we merge to test with, so we can get a shorter test/fix cycle here? Thanks again for trying this out.

alesp commented 1 month ago

I'll get this figured out tomorrow, thanks again for the continued testing. @natros and @alesp are you building from a SDK zip, or using maven? In either case, can I get you a build before we merge to test with, so we can get a shorter test/fix cycle here? Thanks again for trying this out.

Sure, I'd gladly test. I'm building from source, but could test either way, source, zip or maven.

natros commented 1 month ago

I'm testing using snapshots from maven central and if it works I build locally and deploy to a private nexus repository to be used in production. I have been doing this for quite some time with great success. I can pick some PR to test locally.

niloc132 commented 1 month ago

It looks like this 'immutable' code originated with https://github.com/gwtproject/gwt/commit/4c079fb166cb027f77dd1a055ebf797774046d8b, where it actually appears to have been immutable.. except for Lists.set with a collection of more than one item. This caused a later bug and was partially, but not fully removed in https://github.com/gwtproject/gwt/commit/08dc8cd787673a93f97e481aa8535e547c6e208d (see also https://gwt-review.googlesource.com/c/gwt/+/7640/7) with some discussion, but the refactor was apparently not completed?

There isn't a lot of discussion on either point, so I can only make guesses here. Nevertheless, the various accept methods do exactly the same thing now, and it may make sense to just remove the custom collections at some point, with some profiling of the build (maybe after #10007?), and de-duplicate the various accept methods. See https://github.com/gwtproject/gwt/issues/10009 for followup.

I've created a PR that fixes the bug, see https://github.com/gwtproject/gwt/pull/10010. That build is deployed to https://repo.vertispan.com/gwt-snapshot as version 2.12.0-10005-immutable-accept-SNAPSHOT (see for example https://repo.vertispan.com/gwt-snapshot/org/gwtproject/gwt/2.12.0-10005-immutable-accept-SNAPSHOT/), you can add this as a remote repository to test, or build from the branch.

natros commented 1 month ago

I'm trying 2.12.0-10005-immutable-accept-SNAPSHOT but it's failing, this time in a different place.

   Compiling 2 permutations
      Compiling permutation 0...
      [ERROR] An internal compiler exception occurred
com.google.gwt.dev.jjs.InternalCompilerException: Unexpected error during visit.
    at com.google.gwt.dev.jjs.ast.JVisitor.translateException(JVisitor.java:111)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContextImmutable.traverse(JModVisitor.java:173)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemoveImmutable(JModVisitor.java:336)
    at com.google.gwt.dev.jjs.ast.JCaseStatement.traverse(JCaseStatement.java:73)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:88)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:331)
    at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:94)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:139)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:135)
    at com.google.gwt.dev.jjs.ast.JSwitchExpression.traverse(JSwitchExpression.java:52)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:118)
    at com.google.gwt.dev.jjs.ast.JReturnStatement.traverse(JReturnStatement.java:40)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:88)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:331)
    at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:94)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:139)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:135)
    at com.google.gwt.dev.jjs.ast.JMethodBody.traverse(JMethodBody.java:83)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JMethod.visitChildren(JMethod.java:786)
    at com.google.gwt.dev.jjs.ast.JMethod.traverse(JMethod.java:778)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContextImmutable.traverse(JModVisitor.java:169)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemoveImmutable(JModVisitor.java:336)
    at com.google.gwt.dev.jjs.ast.JClassType.traverse(JClassType.java:147)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.ast.JProgram.visitModuleTypes(JProgram.java:1285)
    at com.google.gwt.dev.jjs.ast.JProgram.traverse(JProgram.java:1249)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:361)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:273)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:265)
    at com.google.gwt.dev.jjs.impl.MakeCallsStatic.execImpl(MakeCallsStatic.java:504)
    at com.google.gwt.dev.jjs.impl.MakeCallsStatic.exec(MakeCallsStatic.java:449)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaOneTime(JavaToJavaScriptCompiler.java:1495)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJavaToFixedPoint(JavaToJavaScriptCompiler.java:1431)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.optimizeJava(JavaToJavaScriptCompiler.java:525)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:362)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
    at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
    at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
    at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
    at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.UnsupportedOperationException
    at java.base/java.util.Collections$UnmodifiableList.set(Collections.java:1503)
    at com.google.gwt.dev.util.collect.Lists.set(Lists.java:238)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContextImmutable.replaceMe(JModVisitor.java:157)
    at com.google.gwt.dev.jjs.impl.MakeCallsStatic$RewriteCallSites.endVisit(MakeCallsStatic.java:356)
    at com.google.gwt.dev.jjs.ast.JMethodCall.traverse(JMethodCall.java:268)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContextImmutable.traverse(JModVisitor.java:169)
    ... 50 more
         [ERROR] at Main.java(15): Main$Kind.B.ordinal()
            com.google.gwt.dev.jjs.ast.JMethodCall
         [ERROR] at Main.java(15): case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
            com.google.gwt.dev.jjs.ast.JCaseStatement
         [ERROR] at Main.java(13): {
  case Enum.$ordinal(Main$Kind.A): 
  yield  "1";
  case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
  yield  "2";
  case Main$Kind.G.ordinal(): 
  yield  "7";
  case Main$Kind.H.ordinal(): 
  yield  "8";
  case Main$Kind.I.ordinal(): 
  yield  "9";
  case Main$Kind.J.ordinal(): 
  yield  "10";
  case Main$Kind.K.ordinal(): 
  yield  "11";
  case Main$Kind.L.ordinal(): 
  yield  "12";
  case Main$Kind.M.ordinal(): 
  yield  "13";
  case Main$Kind.N.ordinal(): 
  yield  "14";
  case Main$Kind.O.ordinal(): 
  yield  "15";
}
            com.google.gwt.dev.jjs.ast.JBlock
         [ERROR] at Main.java(13): switch (Enum.$ordinal(kind))  {
  case Enum.$ordinal(Main$Kind.A): 
  yield  "1";
  case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
  yield  "2";
  case Main$Kind.G.ordinal(): 
  yield  "7";
  case Main$Kind.H.ordinal(): 
  yield  "8";
  case Main$Kind.I.ordinal(): 
  yield  "9";
  case Main$Kind.J.ordinal(): 
  yield  "10";
  case Main$Kind.K.ordinal(): 
  yield  "11";
  case Main$Kind.L.ordinal(): 
  yield  "12";
  case Main$Kind.M.ordinal(): 
  yield  "13";
  case Main$Kind.N.ordinal(): 
  yield  "14";
  case Main$Kind.O.ordinal(): 
  yield  "15";
}
            com.google.gwt.dev.jjs.ast.JSwitchExpression
         [ERROR] at Main.java(13): return switch (Enum.$ordinal(kind))  {
  case Enum.$ordinal(Main$Kind.A): 
  yield  "1";
  case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
  yield  "2";
  case Main$Kind.G.ordinal(): 
  yield  "7";
  case Main$Kind.H.ordinal(): 
  yield  "8";
  case Main$Kind.I.ordinal(): 
  yield  "9";
  case Main$Kind.J.ordinal(): 
  yield  "10";
  case Main$Kind.K.ordinal(): 
  yield  "11";
  case Main$Kind.L.ordinal(): 
  yield  "12";
  case Main$Kind.M.ordinal(): 
  yield  "13";
  case Main$Kind.N.ordinal(): 
  yield  "14";
  case Main$Kind.O.ordinal(): 
  yield  "15";
}
            com.google.gwt.dev.jjs.ast.JReturnStatement
         [ERROR] at Main.java(12): {
  return switch (Enum.$ordinal(kind))  {
    case Enum.$ordinal(Main$Kind.A): 
    yield  "1";
    case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
    yield  "2";
    case Main$Kind.G.ordinal(): 
    yield  "7";
    case Main$Kind.H.ordinal(): 
    yield  "8";
    case Main$Kind.I.ordinal(): 
    yield  "9";
    case Main$Kind.J.ordinal(): 
    yield  "10";
    case Main$Kind.K.ordinal(): 
    yield  "11";
    case Main$Kind.L.ordinal(): 
    yield  "12";
    case Main$Kind.M.ordinal(): 
    yield  "13";
    case Main$Kind.N.ordinal(): 
    yield  "14";
    case Main$Kind.O.ordinal(): 
    yield  "15";
  }
}
            com.google.gwt.dev.jjs.ast.JBlock
         [ERROR] at Main.java(12): {
  return switch (Enum.$ordinal(kind))  {
    case Enum.$ordinal(Main$Kind.A): 
    yield  "1";
    case Main$Kind.B.ordinal(), Main$Kind.C.ordinal(), Main$Kind.D.ordinal(), Main$Kind.E.ordinal(), Main$Kind.F.ordinal(): 
    yield  "2";
    case Main$Kind.G.ordinal(): 
    yield  "7";
    case Main$Kind.H.ordinal(): 
    yield  "8";
    case Main$Kind.I.ordinal(): 
    yield  "9";
    case Main$Kind.J.ordinal(): 
    yield  "10";
    case Main$Kind.K.ordinal(): 
    yield  "11";
    case Main$Kind.L.ordinal(): 
    yield  "12";
    case Main$Kind.M.ordinal(): 
    yield  "13";
    case Main$Kind.N.ordinal(): 
    yield  "14";
    case Main$Kind.O.ordinal(): 
    yield  "15";
  }
}
            com.google.gwt.dev.jjs.ast.JMethodBody
         [ERROR] at Main.java(12): pt.ipb.candidaturas.alunos.client.Main.getKind(Lpt/ipb/candidaturas/alunos/client/Main$Kind;)Ljava/lang/String;
            com.google.gwt.dev.jjs.ast.JMethod
         [ERROR] at Main.java(5): pt.ipb.candidaturas.alunos.client.Main (extends Object implements EntryPoint)
            com.google.gwt.dev.jjs.ast.JClassType
         [ERROR] at Unknown(0): <JProgram>
            com.google.gwt.dev.jjs.ast.JProgram
      [ERROR] Unrecoverable exception, shutting down
com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
    at com.google.gwt.dev.javac.CompilationProblemReporter.logAndTranslateException(CompilationProblemReporter.java:106)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:461)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.compilePermutation(JavaToJavaScriptCompiler.java:274)
    at com.google.gwt.dev.CompilePerms.compile(CompilePerms.java:198)
    at com.google.gwt.dev.ThreadedPermutationWorkerFactory$ThreadedPermutationWorker.compile(ThreadedPermutationWorkerFactory.java:50)
    at com.google.gwt.dev.PermutationWorkerFactory$Manager$WorkerThread.run(PermutationWorkerFactory.java:74)
    at java.base/java.lang.Thread.run(Thread.java:1583)
      [ERROR] Not all permutation were compiled , completed (0/2)
alesp commented 1 month ago

I get the same error compiling the example in https://github.com/gwtproject/gwt/issues/10005#issuecomment-2414372572

I tried both building using PR https://github.com/gwtproject/gwt/pull/10010 and using 2.12.0-10005-immutable-accept-SNAPSHOT from repository.

niloc132 commented 1 month ago

Sorry, I missed one, I've updated the branch and the snapshot now, can you test again?

I'm updating the test to try to reproduce the same failure you're seeing, but don't seem to have it right yet.

alesp commented 1 month ago

Example from https://github.com/gwtproject/gwt/issues/10005#issuecomment-2414250116 now compiles,

example from https://github.com/gwtproject/gwt/issues/10005#issuecomment-2414372572 still fails with the same error.

alesp commented 1 month ago

Another note, my example unnecessarily uses CellTable. Same example as in original bug report can be used to reproduce this bug by adding if + return statements in getKind:

private static String getKind(Kind kind) {
    if (Math.random() > .5)
        return "0";
    return switch (kind) {
      case A -> "1";
      case B -> "2";
      case C -> "3";
      case D -> "4";
      case E -> "5";
      case F -> "6";
      case G -> "7";
      case H -> "8";
      case I -> "9";
      case J -> "10";
      case K -> "11";
      case L -> "12";
      case M -> "13";
      case N -> "14";
      case O -> "15";
    };
  }
natros commented 1 month ago

I can confirm that my example is compiled correctly. I did not test the examples provided by @alesp

niloc132 commented 1 month ago

Thank you @alesp, I'm working from that newer example now to reproduce the issue.

niloc132 commented 1 month ago

Thanks again for this report, @alesp, I figured out how to reproduce the issue in tests, and while it took me longer than I'd have liked to nail down, I found that it showed how I missed a necessary endVisit override in UnifyAst to correctly merge separate compliation units.

I've pushed the branch and a new snapshot with the fix.

alesp commented 1 month ago

Thank you @niloc132, all my projects compile ok with this snapshot.

natros commented 1 month ago

I confirm the recent changes can compile @alesp's code presented in this issue