Disallow JsOptional on primitive typed parameters.

Change-Id: Ic9affb24a32317fe0cf99c910c98a9284838bb80
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
index ab8e301..572af74 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
@@ -80,6 +80,11 @@
   }
 
   @Override
+  public boolean isPrimitiveType() {
+    return false;
+  }
+
+  @Override
   public boolean isAbstract() {
     return false;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
index 8cd9505..8e62df3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
@@ -80,6 +80,11 @@
   }
 
   @Override
+  public boolean isPrimitiveType() {
+    return true;
+  }
+
+  @Override
   public boolean isJsType() {
     return false;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
index 57fc036..e3611d2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
@@ -320,6 +320,11 @@
     return "L" + name.replace('.', '/') + ';';
   }
 
+  @Override
+  public boolean isPrimitiveType() {
+    return false;
+  }
+
   public JReferenceType weakenToNullable() {
     if (getUnderlyingType() == this) {
       // Underlying types cannot be weakened.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
index 7a62af4..4dfe990 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
@@ -64,6 +64,7 @@
 
   public abstract boolean isArrayType();
 
+  public abstract boolean isPrimitiveType();
   /**
    * Returns {@code true} if this is {@link JReferenceType.JNullType.INSTANCE}.
    */
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index e822ac2..382212d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -589,7 +589,7 @@
   }
 
   public boolean castSucceedsTrivially(JType fromType, JType toType) {
-    if (fromType instanceof JPrimitiveType && toType instanceof JPrimitiveType) {
+    if (fromType.isPrimitiveType() && toType.isPrimitiveType()) {
       return fromType == toType;
     }
     if (fromType instanceof JReferenceType && toType instanceof JReferenceType) {
@@ -688,7 +688,7 @@
         }
       }
 
-      if (arrayType.getLeafType() instanceof JPrimitiveType) {
+      if (arrayType.getLeafType().isPrimitiveType()) {
         castableDestinationTypes.add(arrayType);
       } else {
         // Class arrays reuse their leaf type castable destination types.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java
index c594100..b0d4990 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java
@@ -24,7 +24,6 @@
 import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
 import com.google.gwt.dev.jjs.ast.JPrefixOperation;
-import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JThrowStatement;
@@ -97,7 +96,7 @@
       return "_Object";
     }
 
-    assert (argType instanceof JPrimitiveType);
+    assert (argType.isPrimitiveType());
     return "_" + argType.getName();
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CompileTimeConstantsReplacer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CompileTimeConstantsReplacer.java
index 0491e08..8761313 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CompileTimeConstantsReplacer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CompileTimeConstantsReplacer.java
@@ -21,7 +21,6 @@
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JFieldRef;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
-import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.thirdparty.guava.common.collect.Maps;
@@ -58,7 +57,7 @@
       // clone it and recursively remove field references, and finally cache the results.
       value = accept(new CloneExpressionVisitor().cloneExpression(field.getInitializer()));
       JType fieldType = field.getType().getUnderlyingType();
-      assert fieldType instanceof JPrimitiveType || fieldType == program.getTypeJavaLangString()
+      assert fieldType.isPrimitiveType() || fieldType == program.getTypeJavaLangString()
           : fieldType.getName() + " is not a primitive nor String";
       if (fieldType != value.getType()) {
         value = new JCastOperation(value.getSourceInfo(), fieldType, value);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index 5a326b9..26df51c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -1789,7 +1789,7 @@
            * this value is not changed.
            */
           // TODO(spoon): use Simplifier.cast to shorten this
-          if ((x.getType() instanceof JPrimitiveType) && (lit instanceof JValueLiteral)) {
+          if (x.getType().isPrimitiveType() && (lit instanceof JValueLiteral)) {
             JPrimitiveType xTypePrim = (JPrimitiveType) x.getType();
             lit = xTypePrim.coerce((JValueLiteral) lit);
           }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java
index e1ecc9a..6e6e158 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java
@@ -110,7 +110,7 @@
 
       // It is a primitive type, perform the necessary coercion.
 
-      assert toType instanceof JPrimitiveType;
+      assert toType.isPrimitiveType();
       /*
        * See JLS 5.1.3: if a cast narrows from one type to another, we must
        * call a narrowing conversion function. EXCEPTION: we currently have no
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplicitUpcastAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplicitUpcastAnalyzer.java
index e38793e..a2d26f0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplicitUpcastAnalyzer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplicitUpcastAnalyzer.java
@@ -93,11 +93,11 @@
 
   @Override
   public void endVisit(JField x, Context ctx) {
-    if (x.getInitializer() == null && !x.isFinal()) {
-      if (!(x.getType() instanceof JPrimitiveType)) {
-        // if it is declared without an initial value, it defaults to null
-        processIfTypesNotEqual(JReferenceType.NULL_TYPE, x.getType(), x.getSourceInfo());
-      }
+    if (x.getInitializer() == null
+        && !x.isFinal()
+        && !x.getType().isPrimitiveType()) {
+      // if it is declared without an initial value, it defaults to null
+      processIfTypesNotEqual(JReferenceType.NULL_TYPE, x.getType(), x.getSourceInfo());
     }
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
index 9a34f4d..a781602 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
@@ -393,6 +393,10 @@
     boolean hasOptionalParameters = false;
     for (JParameter parameter : method.getParams()) {
       if (parameter.isOptional()) {
+        if (parameter.getType().isPrimitiveType()) {
+          logError(method, "JsOptional parameter '%s' in method %s cannot be of primitive type.",
+              parameter.getName(), getMemberDescription(method));
+        }
         hasOptionalParameters = true;
         continue;
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
index fb47e92..ac577f8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
@@ -23,7 +23,6 @@
 import com.google.gwt.dev.jjs.ast.JMethod;
 import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JParameter;
-import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.util.JsniRef;
@@ -75,7 +74,7 @@
       if (fieldName.equals(JsniRef.CLASS)) {
         return type;
 
-      } else if (type instanceof JPrimitiveType) {
+      } else if (type.isPrimitiveType()) {
         errorReporter.reportError("May not refer to fields on primitive types");
         return null;
 
@@ -94,7 +93,7 @@
       errorReporter.reportError("Unresolvable native reference to field '" + fieldName
           + "' in type '" + className + "'");
       return null;
-    } else if (type instanceof JPrimitiveType) {
+    } else if (type.isPrimitiveType()) {
       errorReporter.reportError("May not refer to methods on primitive types");
       return null;
     } else {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java
index 56fc8fd..5145253 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java
@@ -67,7 +67,7 @@
       return false;
     }
     // break up so that result may be coerced to LHS type
-    if (lhsType instanceof JPrimitiveType && rhsType instanceof JPrimitiveType
+    if (lhsType.isPrimitiveType() && rhsType.isPrimitiveType()
         && widenType(lhsType, rhsType) != lhsType) {
       return true;
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index 6380929..d09974f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -39,7 +39,6 @@
 import com.google.gwt.dev.jjs.ast.JNewInstance;
 import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JParameter;
-import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JRuntimeTypeReference;
@@ -629,7 +628,7 @@
       JType leafType = primitiveTypeOrNullTypeOrArray(program, ((JArrayType) type).getLeafType());
       return program.getOrCreateArrayType(leafType, ((JArrayType) type).getDims());
     }
-    if (type instanceof JPrimitiveType) {
+    if (type.isPrimitiveType()) {
       return type;
     }
     return JReferenceType.NULL_TYPE;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
index ff57f5b..46453a4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
@@ -127,7 +127,7 @@
 
     JType type = types.get(key);
     if (type != null) {
-      assert type instanceof JPrimitiveType || type.isNullType() || type.isExternal();
+      assert type.isPrimitiveType() || type.isNullType() || type.isExternal();
       return type;
     }
     assert !(binding instanceof BaseTypeBinding);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java
index 80fd5dd..9c6e22e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java
@@ -133,7 +133,7 @@
       return exp;
     }
 
-    if ((type instanceof JPrimitiveType) && (exp instanceof JValueLiteral)) {
+    if (type.isPrimitiveType() && (exp instanceof JValueLiteral)) {
       // Statically evaluate casting literals.
       JPrimitiveType primitiveType = (JPrimitiveType) type;
       JValueLiteral expLit = (JValueLiteral) exp;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
index 2c4831a..3772b19 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
@@ -94,7 +94,7 @@
    * Determines the type category for a specific type.
    */
   public static TypeCategory typeCategoryForType(JType type, JProgram program) {
-    if (type instanceof JPrimitiveType) {
+    if (type.isPrimitiveType()) {
       if (type == JPrimitiveType.BOOLEAN) {
         return TypeCategory.TYPE_PRIMITIVE_BOOLEAN;
       } else if (type == JPrimitiveType.LONG) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
index 9116dc3..6945f5f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -59,7 +59,6 @@
 import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JNullLiteral;
 import com.google.gwt.dev.jjs.ast.JPermutationDependentValue;
-import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JStringLiteral;
@@ -1630,7 +1629,7 @@
   }
 
   private JType translate(JType type) {
-    if (type instanceof JPrimitiveType) {
+    if (type.isPrimitiveType()) {
       return type;
     }
     return translate((JReferenceType) type);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
index e7edec8..e114806 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
@@ -1505,7 +1505,7 @@
         "  @JsConstructor public Buggy(@JsOptional Object a) {}",
         "  @JsMethod public void fun(int a, Object b, @JsOptional String c) {}",
         "  @JsMethod public void bar(int a, @JsOptional Object b, @JsOptional String c) {}",
-        "  @JsMethod public void baz(@JsOptional int a, @JsOptional Object b) {}",
+        "  @JsMethod public void baz(@JsOptional String a, @JsOptional Object b) {}",
         "}");
 
     assertBuggySucceeds();
@@ -1544,13 +1544,13 @@
     addSnippetImport("jsinterop.annotations.JsOptional");
     addSnippetClassDecl(
         "public static class Buggy {",
-        "   @JsConstructor public Buggy(@JsOptional int a, Object b, @JsOptional String c) {}",
+        "   @JsConstructor public Buggy(@JsOptional String a, Object b, @JsOptional String c) {}",
         "   @JsMethod public void bar(int a, @JsOptional Object b, String c) {}",
         "   @JsMethod public void baz(@JsOptional Object b, String c, Object... os) {}",
         "}");
 
     assertBuggyFails(
-        "Line 7: JsOptional parameter 'b' in method 'EntryPoint.Buggy.EntryPoint$Buggy(int, "
+        "Line 7: JsOptional parameter 'b' in method 'EntryPoint.Buggy.EntryPoint$Buggy(String, "
             + "Object, String)' cannot precede parameters that are not optional.",
         "Line 8: JsOptional parameter 'c' in method 'void EntryPoint.Buggy.bar(int, Object,"
             + " String)' cannot precede parameters that are not optional.",
@@ -1558,6 +1558,21 @@
             + "Object[])' cannot precede parameters that are not optional.");
   }
 
+  public void testJsOptionalOnPrimitiveTypedParametersFails() throws Exception {
+    addSnippetImport("jsinterop.annotations.JsMethod");
+    addSnippetImport("jsinterop.annotations.JsOptional");
+    addSnippetClassDecl(
+        "public static class Buggy {",
+        "  @JsMethod public void m(@JsOptional int i, @JsOptional byte b) {}",
+        "}");
+
+    assertBuggyFails(
+        "Line 6: JsOptional parameter 'b' in method 'void EntryPoint.Buggy.m(int, byte)' cannot be "
+            + "of primitive type.",
+        "Line 6: JsOptional parameter 'i' in method 'void EntryPoint.Buggy.m(int, byte)' cannot be "
+            + "of primitive type.");
+  }
+
   public void testJsOptionalOnNonJsExposedMethodsFails() throws Exception {
     addSnippetImport("jsinterop.annotations.JsProperty");
     addSnippetImport("jsinterop.annotations.JsOptional");