Fix cyclic reuse of final static constants: avoid to "optimize" static field expressions
diff --git a/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java b/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java
index c09532a..340ae73 100644
--- a/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java
+++ b/src/main/java/net/hydromatic/linq4j/expressions/DeterministicCodeOptimizer.java
@@ -189,6 +189,17 @@
     return result;
   }
 
+  @Override
+  public MemberDeclaration visit(FieldDeclaration fieldDeclaration,
+      Expression initializer) {
+    if (Modifier.isStatic(fieldDeclaration.modifier)) {
+      // Avoid optimization of static fields, since we'll have to track order
+      // of static declarations.
+      return fieldDeclaration;
+    }
+    return super.visit(fieldDeclaration, initializer);
+  }
+
   /**
    * Processes the list of declarations and learns final static ones as
    * effectively constant.
@@ -213,26 +224,6 @@
   }
 
   /**
-   * Adds new declarations (e.g. final static fields) to the list of existing
-   * ones.
-   *
-   * @param memberDeclarations existing list of declarations
-   * @return new list of declarations or the same if no modifications required
-   */
-  protected List<MemberDeclaration> optimizeDeclarations(
-      List<MemberDeclaration> memberDeclarations) {
-    if (addedDeclarations.isEmpty()) {
-      return memberDeclarations;
-    }
-    List<MemberDeclaration> newDecls =
-        new ArrayList<MemberDeclaration>(memberDeclarations.size()
-            + addedDeclarations.size());
-    newDecls.addAll(memberDeclarations);
-    newDecls.addAll(addedDeclarations);
-    return newDecls;
-  }
-
-  /**
    * Finds if there exists ready for reuse declaration for given expression.
    *
    * @param expression input expression
diff --git a/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java b/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
index 7082d1c..bb5787b 100644
--- a/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
+++ b/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
@@ -44,10 +44,26 @@
     return optimize(Expressions.return_(null, expr));
   }
 
+  public static BlockStatement optimizeExpression(Expression expr) {
+    return optimizeStatement(Expressions.return_(null, expr));
+  }
+
   public static String optimize(Statement statement) {
+    return optimizeStatement(statement).toString();
+  }
+
+  public static BlockStatement optimizeStatement(Statement statement) {
     BlockBuilder b = new BlockBuilder(true);
-    b.add(statement);
-    return b.toBlock().toString();
+    if (!(statement instanceof BlockStatement)) {
+      b.add(statement);
+    } else {
+      BlockStatement bs = (BlockStatement) statement;
+      for (Statement stmt : bs.statements) {
+        b.add(stmt);
+      }
+    }
+    BlockStatement bs = b.toBlock();
+    return bs;
   }
 
   public static ParameterExpression bool(String name) {
diff --git a/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java b/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java
index 5c44a2d..bda6599 100644
--- a/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java
+++ b/src/test/java/net/hydromatic/linq4j/test/DeterministicTest.java
@@ -90,6 +90,30 @@
             + "}\n"));
   }
 
+  @Test public void testFactorOutBinaryAddSurviesMultipleOptimizations() {
+    assertThat(
+        optimize(optimizeExpression(
+            Expressions.new_(
+                Runnable.class,
+                Collections.<Expression>emptyList(),
+                Expressions.methodDecl(
+                    0,
+                    int.class,
+                    "test",
+                    Collections.<ParameterExpression>emptyList(),
+                    Blocks.toFunctionBlock(Expressions.add(ONE, TWO)))))),
+        equalTo(
+            "{\n"
+            + "  return new Runnable(){\n"
+            + "      int test() {\n"
+            + "        return $L4J$C$1_2;\n"
+            + "      }\n"
+            + "\n"
+            + "      static final int $L4J$C$1_2 = 1 + 2;\n"
+            + "    };\n"
+            + "}\n"));
+  }
+
   @Test public void testFactorOutBinaryAddNameCollision() {
     assertThat(
         optimize(