Optimize a ? true/false : b and a ? b : true/false patterns coming from CASE
diff --git a/src/main/java/net/hydromatic/linq4j/expressions/OptimizeVisitor.java b/src/main/java/net/hydromatic/linq4j/expressions/OptimizeVisitor.java
index e0567eb..42e87b1 100644
--- a/src/main/java/net/hydromatic/linq4j/expressions/OptimizeVisitor.java
+++ b/src/main/java/net/hydromatic/linq4j/expressions/OptimizeVisitor.java
@@ -17,8 +17,9 @@
 */
 package net.hydromatic.linq4j.expressions;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
 
 import static net.hydromatic.linq4j.expressions.ExpressionType.Equal;
 import static net.hydromatic.linq4j.expressions.ExpressionType.NotEqual;
@@ -42,6 +43,21 @@
       Expressions.field(null, Boolean.class, "TRUE");
   public static final Statement EMPTY_STATEMENT = Expressions.statement(null);
 
+  private static final Set<Method> KNOWN_NON_NULL_METHODS
+    = new HashSet<Method>();
+
+  static {
+    for (Class aClass : new Class[]{Boolean.class, Byte.class, Short.class,
+      Integer.class, Long.class, String.class}) {
+      for (Method method : aClass.getMethods()) {
+        if ("valueOf".equals(method.getName())
+            && Modifier.isStatic(method.getModifiers())) {
+          KNOWN_NON_NULL_METHODS.add(method);
+        }
+      }
+    }
+  }
+
   @Override
   public Expression visit(
       TernaryExpression ternary,
@@ -71,6 +87,26 @@
         }
       }
 
+      // a ? true : b  === a || b
+      // a ? false : b === !a && b
+      always = always(expression1);
+      if (always != null && isKnownNotNull(expression2)) {
+        return (always
+                 ? Expressions.orElse(expression0, expression2)
+                 : Expressions.andAlso(Expressions.not(expression0),
+            expression2)).accept(this);
+      }
+
+      // a ? b : true  === !a || b
+      // a ? b : false === a && b
+      always = always(expression2);
+      if (always != null && isKnownNotNull(expression1)) {
+        return (always
+                 ? Expressions.orElse(Expressions.not(expression0),
+                    expression1)
+                 : Expressions.andAlso(expression0, expression1)).accept(this);
+      }
+
       if (expression0 instanceof BinaryExpression
           && (expression0.getNodeType() == ExpressionType.Equal
               || expression0.getNodeType() == ExpressionType.NotEqual)) {
@@ -308,6 +344,21 @@
   }
 
   /**
+   * Verifies if the expression always returns non-null result.
+   * For instance, primitive types cannot contain null values.
+   *
+   * @param expression expression to test
+   * @return true when the expression is known to be not-null
+   */
+  protected boolean isKnownNotNull(Expression expression) {
+    return Primitive.is(expression.getType())
+        || always(expression) != null
+        || (expression instanceof MethodCallExpression
+            && KNOWN_NON_NULL_METHODS.contains(((MethodCallExpression)
+              expression).method));
+  }
+
+  /**
    * Treats two expressions equal even if they represent different null types
    */
   private static boolean eq(Expression a, Expression b) {
diff --git a/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java b/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
index f4f9750..4565143 100644
--- a/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
+++ b/src/test/java/net/hydromatic/linq4j/test/BlockBuilderBase.java
@@ -36,6 +36,11 @@
   public static final Expression TRUE = Expressions.constant(true);
   public static final Expression FALSE = Expressions.constant(false);
 
+  public static final Expression TRUE_B =
+      Expressions.field(null, Boolean.class, "TRUE");
+  public static final Expression FALSE_B =
+      Expressions.field(null, Boolean.class, "FALSE");
+
   public static String optimize(Expression expr) {
     return optimize(Expressions.return_(null, expr));
   }
diff --git a/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java b/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java
index c840843..5d73fc2 100644
--- a/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java
+++ b/src/test/java/net/hydromatic/linq4j/test/OptimizerTest.java
@@ -83,6 +83,61 @@
   }
 
   @Test
+  public void optimizeTernaryAtrueB() {
+    // a ? true : b  === a || b
+    assertEquals("{\n  return a || b;\n}\n",
+        optimize(Expressions.condition(
+            Expressions.parameter(boolean.class, "a"),
+            TRUE, Expressions.parameter(boolean.class, "b"))));
+  }
+
+  @Test
+  public void optimizeTernaryAtrueNull() {
+    // a ? Boolean.TRUE : null  === a ? Boolean.TRUE : (Boolean) null
+    assertEquals("{\n  return a ? Boolean.TRUE : (Boolean) null;\n}\n",
+        optimize(Expressions.condition(
+            Expressions.parameter(boolean.class, "a"),
+            TRUE_B, Expressions.constant(null, Boolean.class))));
+  }
+
+  @Test
+  public void optimizeTernaryAtrueBoxed() {
+    // a ? Boolean.TRUE : Boolean.valueOf(b)  === a || b
+    assertEquals("{\n  return a || Boolean.valueOf(b);\n}\n",
+        optimize(Expressions.condition(
+            Expressions.parameter(boolean.class, "a"),
+            TRUE_B, Expressions.call(Boolean.class, "valueOf",
+            Expressions.parameter(boolean.class, "b")))));
+  }
+
+  @Test
+  public void optimizeTernaryABtrue() {
+    // a ? b : true  === !a || b
+    assertEquals("{\n  return !a || b;\n}\n",
+        optimize(Expressions.condition(
+            Expressions.parameter(boolean.class, "a"),
+            Expressions.parameter(boolean.class, "b"), TRUE)));
+  }
+
+  @Test
+  public void optimizeTernaryAfalseB() {
+    // a ? false : b === !a && b
+    assertEquals("{\n  return !a && b;\n}\n",
+        optimize(Expressions.condition(
+            Expressions.parameter(boolean.class, "a"),
+            FALSE, Expressions.parameter(boolean.class, "b"))));
+  }
+
+  @Test
+  public void optimizeTernaryABfalse() {
+    // a ? b : false === a && b
+    assertEquals("{\n  return a && b;\n}\n",
+        optimize(Expressions.condition(
+            Expressions.parameter(boolean.class, "a"),
+            Expressions.parameter(boolean.class, "b"), FALSE)));
+  }
+
+  @Test
   public void optimizeTernaryInEqualABCeqB() {
     // (v ? (Integer) null : inp0_) == null
     assertEquals("{\n  return v || inp0_ == null;\n}\n",
@@ -115,7 +170,7 @@
 
   @Test
   public void optimizeTernaryAeqBAB() {
-    // a == b ? b : a
+    // a == b ? a : b
     ParameterExpression a = Expressions.parameter(boolean.class, "a");
     ParameterExpression b = Expressions.parameter(boolean.class, "b");
     assertEquals("{\n  return b;\n}\n",