Fix https://github.com/julianhyde/linq4j/issues/27, "Incorrectly inlines non-final variable".
diff --git a/src/main/java/net/hydromatic/linq4j/Linq4j.java b/src/main/java/net/hydromatic/linq4j/Linq4j.java
index b854f64..0b2ff67 100644
--- a/src/main/java/net/hydromatic/linq4j/Linq4j.java
+++ b/src/main/java/net/hydromatic/linq4j/Linq4j.java
@@ -34,7 +34,7 @@
   private static final Method AUTO_CLOSEABLE_CLOSE_METHOD =
       getMethod("java.lang.AutoCloseable", "close");
 
-  private static Method getMethod(String className, String methodName,
+  public static Method getMethod(String className, String methodName,
       Class... parameterTypes) {
     try {
       return Class.forName(className).getMethod(methodName, parameterTypes);
diff --git a/src/main/java/net/hydromatic/linq4j/expressions/BlockBuilder.java b/src/main/java/net/hydromatic/linq4j/expressions/BlockBuilder.java
index 207705a..2170594 100644
--- a/src/main/java/net/hydromatic/linq4j/expressions/BlockBuilder.java
+++ b/src/main/java/net/hydromatic/linq4j/expressions/BlockBuilder.java
@@ -231,11 +231,10 @@
   }
 
   protected boolean isSafeForReuse(DeclarationStatement decl) {
-    return (decl.modifiers & Modifier.FINAL) != 0
-           && decl.initializer != null;
+    return (decl.modifiers & Modifier.FINAL) != 0;
   }
 
-  protected void addExpresisonForReuse(DeclarationStatement decl) {
+  protected void addExpressionForReuse(DeclarationStatement decl) {
     if (isSafeForReuse(decl)) {
       Expression expr = normalizeDeclaration(decl);
       expressionForReuse.put(expr, decl);
@@ -282,7 +281,7 @@
       if (!variables.add(name)) {
         throw new AssertionError("duplicate variable " + name);
       }
-      addExpresisonForReuse(decl);
+      addExpressionForReuse(decl);
     }
   }
 
@@ -343,11 +342,15 @@
         DeclarationStatement statement = (DeclarationStatement) oldStatement;
         final Slot slot = useCounter.map.get(statement.parameter);
         int count = slot == null ? Integer.MAX_VALUE - 10 : slot.count;
-        if (count > 1 && isSafeForReuse(statement)
-            && isSimpleExpression(statement.initializer)) {
+        if (count > 1 && isSimpleExpression(statement.initializer)) {
           // Inline simple final constants
           count = 1;
         }
+        if (!isSafeForReuse(statement)) {
+          // Don't inline variables that are not final. They might be assigned
+          // more than once.
+          count = 100;
+        }
         if (statement.parameter.name.startsWith("_")) {
           // Don't inline variables whose name begins with "_". This
           // is a hacky way to prevent inlining. E.g.
@@ -397,7 +400,7 @@
           }
           if (oldStatement != OptimizeVisitor.EMPTY_STATEMENT) {
             if (oldStatement instanceof DeclarationStatement) {
-              addExpresisonForReuse((DeclarationStatement) oldStatement);
+              addExpressionForReuse((DeclarationStatement) oldStatement);
             }
             statements.add(oldStatement);
           }
diff --git a/src/test/java/net/hydromatic/linq4j/test/InlinerTest.java b/src/test/java/net/hydromatic/linq4j/test/InlinerTest.java
index 185e2c1..17af215 100644
--- a/src/test/java/net/hydromatic/linq4j/test/InlinerTest.java
+++ b/src/test/java/net/hydromatic/linq4j/test/InlinerTest.java
@@ -19,12 +19,16 @@
 
 import net.hydromatic.linq4j.expressions.*;
 
+import org.hamcrest.CoreMatchers;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.lang.reflect.Modifier;
+
 import static net.hydromatic.linq4j.test.BlockBuilderBase.*;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
 /**
  * Tests expression inlining in BlockBuilder.
@@ -106,12 +110,28 @@
   }
 
   @Test public void testAssignInConditionOptimizedOut() {
+    checkAssignInConditionOptimizedOut(Modifier.FINAL,
+        "{\n"
+        + "  return 1 != a ? b : c;\n"
+        + "}\n");
+  }
+
+  @Test public void testAssignInConditionNotOptimizedWithoutFinal() {
+    checkAssignInConditionOptimizedOut(0,
+        "{\n"
+        + "  int t;\n"
+        + "  return (t = 1) != a ? b : c;\n"
+        + "}\n");
+  }
+
+  void checkAssignInConditionOptimizedOut(int modifiers, String s) {
     // int t;
     // return (t = 1) != a ? b : c
     final BlockBuilder builder = new BlockBuilder(true);
-    final ParameterExpression t = Expressions.parameter(int.class, "t");
+    final ParameterExpression t =
+        Expressions.parameter(int.class, "t");
 
-    builder.add(Expressions.declare(0, t, null));
+    builder.add(Expressions.declare(modifiers, t, null));
 
     Expression v = builder.append("v",
         Expressions.makeTernary(ExpressionType.Conditional,
@@ -121,11 +141,8 @@
             Expressions.parameter(int.class, "b"),
             Expressions.parameter(int.class, "c")));
     builder.add(Expressions.return_(null, v));
-    assertEquals(
-        "{\n"
-        + "  return 1 != a ? b : c;\n"
-        + "}\n",
-        Expressions.toString(builder.toBlock()));
+    assertThat(Expressions.toString(builder.toBlock()),
+        CoreMatchers.equalTo(s));
   }
 
   @Test public void testAssignInConditionMultipleUsageNonOptimized() {
diff --git a/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java b/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java
index 8ea31c1..b31e996 100644
--- a/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java
+++ b/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java
@@ -17,12 +17,17 @@
 */
 package net.hydromatic.linq4j.test;
 
+import net.hydromatic.linq4j.Linq4j;
 import net.hydromatic.linq4j.expressions.*;
 
 import org.junit.Test;
 
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
 import static net.hydromatic.linq4j.test.BlockBuilderBase.*;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.*;
 
 /**
@@ -659,6 +664,78 @@
     assertEquals("{\n  return false;\n}\n",
         optimize(Expressions.call(Boolean.class, "valueOf", FALSE)));
   }
+
+  @Test public void testAssign() {
+    // long x = 0;
+    // final long y = System.currentTimeMillis();
+    // if (System.nanoTime() > 0) {
+    //   x = y;
+    // }
+    // System.out.println(x);
+    //
+    // In bug https://github.com/julianhyde/linq4j/issues/27, this was
+    // incorrectly optimized to
+    //
+    // if (System.nanoTime() > 0L) {
+    //    System.currentTimeMillis();
+    // }
+    // System.out.println(0L);
+    final ParameterExpression x_ = Expressions.parameter(long.class, "x");
+    final ParameterExpression y_ = Expressions.parameter(long.class, "y");
+    final Method mT = Linq4j.getMethod("java.lang.System", "currentTimeMillis");
+    final Method mNano = Linq4j.getMethod("java.lang.System", "nanoTime");
+    final ConstantExpression zero = Expressions.constant(0L);
+    assertThat(
+        optimize(
+            Expressions.block(
+                Expressions.declare(0, x_, zero),
+                Expressions.declare(Modifier.FINAL, y_, Expressions.call(mT)),
+                Expressions.ifThen(
+                    Expressions.greaterThan(Expressions.call(mNano), zero),
+                    Expressions.statement(Expressions.assign(x_, y_))),
+                Expressions.statement(
+                    Expressions.call(
+                        Expressions.field(null, System.class, "out"),
+                        "println",
+                        x_)))),
+        equalTo(
+            "{\n"
+            + "  long x = 0L;\n"
+            + "  if (System.nanoTime() > 0L) {\n"
+            + "    x = System.currentTimeMillis();\n"
+            + "  }\n"
+            + "  System.out.println(x);\n"
+            + "}\n"));
+  }
+
+  @Test public void testAssign2() {
+    // long x = 0;
+    // final long y = System.currentTimeMillis();
+    // if (System.currentTimeMillis() > 0) {
+    //   x = y;
+    // }
+    //
+    // Make sure we don't fold two calls to System.currentTimeMillis into one.
+    final ParameterExpression x_ = Expressions.parameter(long.class, "x");
+    final ParameterExpression y_ = Expressions.parameter(long.class, "y");
+    final Method mT = Linq4j.getMethod("java.lang.System", "currentTimeMillis");
+    final ConstantExpression zero = Expressions.constant(0L);
+    assertThat(
+        optimize(
+            Expressions.block(
+                Expressions.declare(0, x_, zero),
+                Expressions.declare(Modifier.FINAL, y_, Expressions.call(mT)),
+                Expressions.ifThen(
+                    Expressions.greaterThan(Expressions.call(mT), zero),
+                    Expressions.statement(Expressions.assign(x_, y_))))),
+        equalTo(
+            "{\n"
+            + "  long x = 0L;\n"
+            + "  if (System.currentTimeMillis() > 0L) {\n"
+            + "    x = System.currentTimeMillis();\n"
+            + "  }\n"
+            + "}\n"));
+  }
 }
 
 // End OptimizerTest.java