Fixes JsFunction to be instance of Function.

This makes the generated functions from JsFunction
to behave more like a real function.

In order to achieve that we replaced the parent of the class
to be the javascript Function.prototype. This requires us to
not support extending other classes from JsFunction classes.

Also we prevented other inheritance scenarios like implementing
multiple interfaces from the implementation so that in the future
we can replace the generated code to be a real function that is
not __proto__ treated by putting the instance methods to the
generated function instead.

Change-Id: I4dcb519cf96887072d5a1771fe891574d7d6b101
diff --git a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
index 7072a9f..9236164 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
@@ -90,8 +90,6 @@
   public static final String ERR_JS_TYPE_WITH_PROTOTYPE_SET_NOT_ALLOWED_ON_CLASS_TYPES = "@JsType with prototype set not allowed on class types";
   public static final String ERR_JS_FUNCTION_ONLY_ALLOWED_ON_FUNCTIONAL_INTERFACE =
       "@JsFunction is only allowed on functional interface";
-  public static final String ERR_JS_FUNCTION_INTERFACE_CANNOT_EXTEND_ANY_INTERFACE =
-      "Interface annotated as @JsFunction cannot extend any other interfaces";
   public static final String ERR_JS_FUNCTION_CANNOT_HAVE_DEFAULT_METHODS =
       "JsFunction cannot have default methods";
   static boolean LINT_MODE = false;
@@ -247,9 +245,6 @@
       if (binding.methods().length > 1) {
         errorOn(type, ERR_JS_FUNCTION_CANNOT_HAVE_DEFAULT_METHODS);
       }
-      if (binding.superInterfaces().length > 0) {
-        errorOn(type, ERR_JS_FUNCTION_INTERFACE_CANNOT_EXTEND_ANY_INTERFACE);
-      }
     }
 
     private void checkJsType(TypeDeclaration type, TypeBinding typeBinding) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
index 12dc0b1..823554d 100755
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
@@ -372,14 +372,12 @@
     if (isJsFunction()) {
       return true;
     }
-    if (getSuperClass() != null && getSuperClass().isOrExtendsJsFunction()) {
-      return true;
-    }
     for (JInterfaceType subInterface : getImplements()) {
-      if (subInterface.isOrExtendsJsFunction()) {
+      if (subInterface.isJsFunction()) {
         return true;
       }
     }
+    // We don't need to recurse as inheritance is not supported by JsFunction.
     return false;
   }
 
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 60f346f..54974e4 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
@@ -22,7 +22,6 @@
 import com.google.gwt.thirdparty.guava.common.base.Objects;
 import com.google.gwt.thirdparty.guava.common.base.Predicate;
 import com.google.gwt.thirdparty.guava.common.base.Strings;
-import com.google.gwt.thirdparty.guava.common.collect.Collections2;
 import com.google.gwt.thirdparty.guava.common.collect.HashMultimap;
 import com.google.gwt.thirdparty.guava.common.collect.ImmutableList;
 import com.google.gwt.thirdparty.guava.common.collect.ImmutableSetMultimap;
@@ -814,39 +813,6 @@
     return (type.getSuperClass() != null) ? getJsFunctionMethod(type.getSuperClass()) : null;
   }
 
-  /**
-   * Get all implemented interfaces of {@code type}.
-   */
-  public Collection<JInterfaceType> getImplementedInterfaces(JDeclaredType type) {
-    Multimap<String, String> implementedInterfaces =
-        (type instanceof JClassType) ? implementedInterfacesByClass : superInterfacesByInterface;
-    return Collections2.transform(implementedInterfaces.get(type.getName()),
-        new Function<String, JInterfaceType>() {
-          @Override
-          public JInterfaceType apply(String typeName) {
-            JReferenceType referenceType = referenceTypesByName.get(typeName);
-            assert (referenceType instanceof JInterfaceType);
-            return (JInterfaceType) referenceType;
-          }
-        }
-    );
-  }
-
-  /**
-   * Get all implemented JsFunction interfaces of {@code type}.
-   * After JsInteropRestrictionChecker, jsFunctions.size() <= 1 would always be true.
-   */
-  public Collection<JInterfaceType> getImplementedJsFunctions(JDeclaredType type) {
-    Collection<JInterfaceType> jsFunctions =
-        Collections2.filter(getImplementedInterfaces(type), new Predicate<JInterfaceType>() {
-          @Override
-          public boolean apply(JInterfaceType implementedInterface) {
-            return implementedInterface.isJsFunction();
-          }
-        });
-    return jsFunctions;
-  }
-
   public JMethod getInstanceMethodBySignature(JClassType type, String signature) {
     return getOrCreateInstanceMethodsBySignatureForType(type).get(signature);
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index f3a2671..9717270 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -2553,6 +2553,9 @@
       // check if there's an overriding prototype
       JInterfaceType jsPrototypeIntf = JProgram.maybeGetJsTypeFromPrototype(superClass);
       String jsPrototype = jsPrototypeIntf != null ? jsPrototypeIntf.getJsPrototype() : null;
+      if (x.isOrExtendsJsFunction()) {
+        jsPrototype = "Function";
+      }
 
       List<JsExpression> defineClassArguments = Lists.newArrayList();
 
@@ -2562,6 +2565,7 @@
         defineClassArguments.add(convertJavaLiteral(superTypeId));
       } else {
         // setup extension of native JS object
+        // TODO(goktug): need to stash Object methods to the prototype as they are not inhertied.
         defineClassArguments.add(createJsQualifier(jsPrototype, x.getSourceInfo()));
       }
       JsExpression castMap = generateCastableTypeMap(x);
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 56ec06b..80c8fd4 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
@@ -31,18 +31,15 @@
 import com.google.gwt.dev.jjs.ast.JStatement;
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JVisitor;
-import com.google.gwt.thirdparty.guava.common.base.Function;
 import com.google.gwt.thirdparty.guava.common.base.Predicate;
 import com.google.gwt.thirdparty.guava.common.collect.FluentIterable;
 import com.google.gwt.thirdparty.guava.common.collect.Iterables;
 import com.google.gwt.thirdparty.guava.common.collect.Maps;
-import com.google.gwt.thirdparty.guava.common.collect.Ordering;
 import com.google.gwt.thirdparty.guava.common.collect.Sets;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedSet;
 
 /**
  * Checks and throws errors for invalid JsInterop constructs.
@@ -99,7 +96,7 @@
     currentType = x;
 
     checkJsFunctionHierarchy(x);
-    checkJsFunctionJsTypeCollision(x);
+
     if (currentType instanceof JInterfaceType) {
       checkJsTypeHierarchy((JInterfaceType) currentType);
     } else {
@@ -330,27 +327,43 @@
   }
 
   private void checkJsFunctionHierarchy(JDeclaredType type) {
-    SortedSet<String> implementedJsFunctions =
-        FluentIterable.from(jprogram.typeOracle.getImplementedJsFunctions(type)).transform(
-        new Function<JInterfaceType, String>() {
-          @Override
-          public String apply(JInterfaceType type) {
-            return type.getName();
-          }
-        }).toSortedSet(Ordering.natural());
-    if (implementedJsFunctions.size() > 1) {
-      logError("'%s' implements more than one JsFunction interfaces: %s", type.getName(),
-          implementedJsFunctions);
+    if (!type.isOrExtendsJsFunction()) {
+      return;
+    }
+
+    List<JInterfaceType> implementedInterfaces = type.getImplements();
+
+    if (type.isJsFunction()) {
+      if (implementedInterfaces.size() > 0) {
+        logError("JsFunction '%s' cannot extend other interfaces.", type);
+      }
+      if (type.isJsType()) {
+        logError("'%s' cannot be both a JsFunction and a JsType at the same time.", type);
+      }
+      return;
+    }
+
+    if (type instanceof JInterfaceType) {
+      logError("Interface '%s' cannot extend a JsFunction interface.", type);
+      return;
+    }
+
+    if (implementedInterfaces.size() != 1) {
+      logError("JsFunction implementation '%s' cannot implement more than one interface.", type);
+    }
+
+    if (type.isJsType()) {
+      logError("'%s' cannot be both a JsFunction implementation and a JsType at the same time.",
+          type);
+    }
+
+    if (type.getSuperClass() != jprogram.getTypeJavaLangObject()) {
+      logError("JsFunction implementation '%s' cannot extend a class.", type);
     }
   }
 
-  // To prevent potential name collisions, we disallow JsFunction implementations to be also a
-  // JsType.
-  private void checkJsFunctionJsTypeCollision(JDeclaredType type) {
-    if (type.isOrExtendsJsType() && type.isOrExtendsJsFunction()) {
-      logError("'%s' cannot be annotated as (or extend) both a @JsFunction and a @JsType at the "
-          + "same time.", type.getName());
-    }
+  private void logError(String format, JType type) {
+    logError(format, type.getName());
   }
 
   private void logError(String format, Object... args) {
diff --git a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
index 03b9798..d3575f2 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
@@ -709,18 +709,6 @@
         "Line 2: " + JSORestrictionsChecker.ERR_JS_FUNCTION_ONLY_ALLOWED_ON_FUNCTIONAL_INTERFACE);
   }
 
-  public void testJsFunctionNotOnInterfaceWithSuperInterfaces() {
-    StringBuilder buggyCode = new StringBuilder();
-    buggyCode.append("import com.google.gwt.core.client.js.JsFunction;\n");
-    buggyCode.append("import java.io.Serializable;\n");
-    buggyCode.append("@JsFunction public interface Buggy extends Serializable {\n");
-    buggyCode.append("int foo(int x);\n");
-    buggyCode.append("}\n");
-
-    shouldGenerateError(buggyCode,
-        "Line 3: " + JSORestrictionsChecker.ERR_JS_FUNCTION_INTERFACE_CANNOT_EXTEND_ANY_INTERFACE);
-  }
-
   public void testJsFunctionNotOnInterfaceWithDefaultMethod() {
     StringBuilder buggyCode = new StringBuilder();
     buggyCode.append("import com.google.gwt.core.client.js.JsFunction;\n");
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 c932fae..8588dd9 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
@@ -770,293 +770,112 @@
     assertBuggySucceeds();
   }
 
-  public void testJsFunctionSingleInterfaceSucceeds() throws Exception {
-    addAll(jsFunctionInterface1);
+  public void testJsFunctionWithNoExtendsSucceeds() throws Exception {
+    addSnippetImport("com.google.gwt.core.client.js.JsFunction");
     addSnippetClassDecl(
-        "public static class Buggy implements MyJsFunctionInterface1 {",
+        "@JsFunction",
+        "public interface Buggy {",
+        "  void foo();",
+        "}");
+
+    assertBuggySucceeds();
+  }
+
+  public void testJsFunctionExtendsInterfaceFails() throws Exception {
+    addSnippetImport("com.google.gwt.core.client.js.JsFunction");
+    addSnippetClassDecl(
+        "interface AnotherInterface {}",
+        "@JsFunction",
+        "public interface Buggy extends AnotherInterface {",
+        "  void foo();",
+        "}");
+
+    assertBuggyFails("JsFunction 'test.EntryPoint$Buggy' cannot extend other interfaces.");
+  }
+
+  public void testJsFunctionExtendedByInterfaceFails() throws Exception {
+    addAll(jsFunctionInterface);
+
+    addSnippetClassDecl("public interface Buggy extends MyJsFunctionInterface {}");
+
+    assertBuggyFails("Interface 'test.EntryPoint$Buggy' cannot extend a JsFunction interface.");
+  }
+
+  public void testJsFunctionMarkedAsJsTypeFails() throws Exception {
+    addSnippetImport("com.google.gwt.core.client.js.JsType");
+    addSnippetImport("com.google.gwt.core.client.js.JsFunction");
+    addSnippetClassDecl(
+        "@JsFunction @JsType",
+        "public interface Buggy {",
+        "  void foo();",
+        "}");
+
+    assertBuggyFails(
+        "'test.EntryPoint$Buggy' cannot be both a JsFunction and a JsType at the same time.");
+  }
+
+  public void testJsFunctionImplementationWithSingleInterfaceSucceeds() throws Exception {
+    addAll(jsFunctionInterface);
+    addSnippetClassDecl(
+        "public static class Buggy implements MyJsFunctionInterface {",
         "  public int foo(int x) { return 0; }",
         "}");
 
     assertBuggySucceeds();
   }
 
-  public void testJsFunctionOneJsFunctionAndOneNonJsFunctionSucceeds() throws Exception {
-    addAll(jsFunctionInterface1, plainInterface);
+  public void testJsFunctionImplementationWithMultipleSuperInterfacesFails() throws Exception {
+    addAll(jsFunctionInterface);
     addSnippetClassDecl(
-        "public static class Buggy implements MyJsFunctionInterface1, MyPlainInterface {",
-        "  public int foo(int x) { return 0; }",
-        "}");
-
-    assertBuggySucceeds();
-  }
-
-  public void testJsFunctionSameJsFunctionFromSuperClassAndSuperInterfaceSucceeds()
-      throws Exception {
-    addAll(jsFunctionInterface1, plainInterface, jsFunctionInterfaceImpl);
-    addSnippetClassDecl(
-        "public static class Buggy extends MyJsFunctionInterfaceImpl ",
-        "implements MyJsFunctionInterface1, MyPlainInterface {",
-        "  public int foo(int x) { return 0; }",
-        "}");
-
-    assertBuggySucceeds();
-  }
-
-  public void testJsFunctionSameJsFunctionFromSuperInterfaceAndSuperSuperInterfaceSucceeds()
-      throws Exception {
-    addAll(jsFunctionInterface3, jsFunctionSubSubInterface, jsFunctionSubInterface);
-    addSnippetClassDecl(
-        "public static class Buggy implements MyJsFunctionInterface3,",
-        "MyJsFunctionSubSubInterface {",
-        "  public int foo(int x) { return 0; }",
-        "}");
-
-    assertBuggySucceeds();
-  }
-
-  public void testJsFunctionMultipleSuperInterfacesFails() throws Exception {
-    addAll(jsFunctionInterface1, jsFunctionInterface2);
-    addSnippetClassDecl(
-        "public static class Buggy implements MyJsFunctionInterface1, MyJsFunctionInterface2 {",
+        "interface AnotherInterface {}",
+        "public static class Buggy implements MyJsFunctionInterface, AnotherInterface {",
         "  public int foo(int x) { return 0; }",
         "  public int bar(int x) { return 0; }",
         "}");
 
-    assertBuggyFails(
-        "'test.EntryPoint$Buggy' implements more than one JsFunction interfaces: "
-        + "[test.MyJsFunctionInterface1, test.MyJsFunctionInterface2]");
+    assertBuggyFails("JsFunction implementation 'test.EntryPoint$Buggy' cannot implement more than "
+        + "one interface.");
   }
 
-  public void testJsFunctionMultipleInterfacesWithSameSignatureFails() throws Exception {
-    addAll(jsFunctionInterface1, jsFunctionInterface3);
+  public void testJsFunctionImplementationWithSuperClassFails() throws Exception {
+    addAll(jsFunctionInterface);
     addSnippetClassDecl(
-        "public static class Buggy implements MyJsFunctionInterface1, MyJsFunctionInterface3 {",
+        "public static class BaseClass {}",
+        "public static class Buggy extends BaseClass implements MyJsFunctionInterface {",
         "  public int foo(int x) { return 0; }",
         "}");
 
-    assertBuggyFails("'test.EntryPoint$Buggy' implements more than one JsFunction interfaces: "
-        + "[test.MyJsFunctionInterface1, test.MyJsFunctionInterface3]");
+    assertBuggyFails("JsFunction implementation 'test.EntryPoint$Buggy' cannot extend a class.");
   }
 
-  public void testJsFunctionFromSuperClassAndSuperInterfaceFails() throws Exception {
-    addAll(jsFunctionInterface1, jsFunctionInterface3, jsFunctionInterfaceImpl);
+  public void testJsFunctionImplementationMarkedAsJsTypeFails() throws Exception {
+    addAll(jsFunctionInterface);
+    addSnippetImport("com.google.gwt.core.client.js.JsType");
     addSnippetClassDecl(
-        "public static class Buggy extends MyJsFunctionInterfaceImpl ",
-        "implements MyJsFunctionInterface3 {",
+        "@JsType",
+        "public static class Buggy implements MyJsFunctionInterface {",
         "  public int foo(int x) { return 0; }",
         "}");
 
     assertBuggyFails(
-        "'test.EntryPoint$Buggy' implements more than one JsFunction interfaces: "
-        + "[test.MyJsFunctionInterface1, test.MyJsFunctionInterface3]");
+        "'test.EntryPoint$Buggy' cannot be both a JsFunction implementation and a JsType at the "
+        + "same time.");
   }
 
-  public void testJsFunctionFromSuperClassAndSuperSuperInterfaceFails() throws Exception {
-    addAll(jsFunctionSubInterface, jsFunctionInterface1, jsFunctionInterfaceImpl,
-        jsFunctionInterface3);
-    addSnippetClassDecl(
-        "public static class Buggy extends MyJsFunctionInterfaceImpl ",
-        "implements MyJsFunctionSubInterface {",
-        "  public int foo(int x) { return 0; }",
-        "}");
-
-    assertBuggyFails(
-        "'test.EntryPoint$Buggy' implements more than one JsFunction interfaces: "
-        + "[test.MyJsFunctionInterface1, test.MyJsFunctionInterface3]");
-  }
-
-  public void testJsFunctionFromSuperInterfaceAndSuperSuperSuperInterfaceFails() throws Exception {
-    addAll(jsFunctionSubInterface, jsFunctionInterface1, jsFunctionSubSubInterface,
-        jsFunctionInterface3);
-    addSnippetClassDecl(
-        "public static class Buggy implements MyJsFunctionInterface1, ",
-        "MyJsFunctionSubSubInterface {",
-        "  public int foo(int x) { return 0; }",
-        "}");
-
-    assertBuggyFails(
-        "'test.EntryPoint$Buggy' implements more than one JsFunction interfaces: "
-        + "[test.MyJsFunctionInterface1, test.MyJsFunctionInterface3]");
-  }
-
-  public void testJsFunctionBuggyInterfaceFails() throws Exception {
-    addAll(buggyInterfaceExtendsMultipleInterfaces, jsFunctionInterface1, jsFunctionInterface2);
-    addSnippetClassDecl("public static class Buggy {}");
-
-    assertBuggyFails(
-        "'test.MyBuggyInterface' implements more than one JsFunction interfaces: "
-        + "[test.MyJsFunctionInterface1, test.MyJsFunctionInterface2]");
-  }
-
-  public void testJsFunctionJsTypeCollisionFails1() throws Exception {
-    addAll(buggyInterfaceBothJsFunctionAndJsType);
-    addSnippetClassDecl(
-        "public static class Buggy implements MyBuggyInterface2 {",
-        "  public int foo(int x) { return x; }",
-        "}");
-
-    assertBuggyFails(
-        "'test.EntryPoint$Buggy' cannot be annotated as (or extend) both a @JsFunction and a "
-        + "@JsType at the same time.",
-        "'test.MyBuggyInterface2' cannot be annotated as (or extend) both a @JsFunction and a "
-        + "@JsType at the same time.");
-  }
-
-  public void testJsFunctionJsTypeCollisionFails2() throws Exception {
-    addAll(jsTypeInterface, jsFunctionInterfaceImpl, jsFunctionInterface1);
-    addSnippetClassDecl(
-        "public static class Buggy extends MyJsFunctionInterfaceImpl ",
-        "implements MyJsTypeInterface {}");
-
-    assertBuggyFails(
-        "'test.EntryPoint$Buggy' cannot be annotated as (or extend) both a "
-        + "@JsFunction and a @JsType at the same time.");
-  }
-
-  // uncomment after isOrExtendsJsType() is fixed.
-//  public void testJsFunctionJsTypeCollisionFails3() throws Exception {
-//    addAll(jsTypeClass, jsFunctionInterface1);
-//    addSnippetClassDecl(
-//        "public static class Buggy extends MyJsTypeClass implements MyJsFunctionInterface1 {\n",
-//        "public int foo(int x) { return 0; }\n",
-//        "}\n");
-//    assertBuggyFails();
-//  }
-
-  private static final MockJavaResource jsFunctionInterface1 = new MockJavaResource(
-      "test.MyJsFunctionInterface1") {
+  private static final MockJavaResource jsFunctionInterface = new MockJavaResource(
+      "test.MyJsFunctionInterface") {
     @Override
     public CharSequence getContent() {
       StringBuilder code = new StringBuilder();
       code.append("package test;\n");
       code.append("import com.google.gwt.core.client.js.JsFunction;\n");
-      code.append("@JsFunction public interface MyJsFunctionInterface1 {\n");
+      code.append("@JsFunction public interface MyJsFunctionInterface {\n");
       code.append("int foo(int x);\n");
       code.append("}\n");
       return code;
     }
   };
 
-  private static final MockJavaResource jsFunctionInterface2 = new MockJavaResource(
-      "test.MyJsFunctionInterface2") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("import com.google.gwt.core.client.js.JsFunction;\n");
-      code.append("@JsFunction public interface MyJsFunctionInterface2 {\n");
-      code.append("int bar(int x);\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource jsFunctionInterface3 = new MockJavaResource(
-      "test.MyJsFunctionInterface3") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("import com.google.gwt.core.client.js.JsFunction;\n");
-      code.append("@JsFunction public interface MyJsFunctionInterface3 {\n");
-      code.append("int foo(int x);\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource plainInterface = new MockJavaResource(
-      "test.MyPlainInterface") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("public interface MyPlainInterface {\n");
-      code.append("int foo(int x);\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource jsFunctionSubInterface = new MockJavaResource(
-      "test.MyJsFunctionSubInterface") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("public interface MyJsFunctionSubInterface extends MyJsFunctionInterface3 {\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource jsFunctionSubSubInterface = new MockJavaResource(
-      "test.MyJsFunctionSubSubInterface") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append(
-          "public interface MyJsFunctionSubSubInterface extends MyJsFunctionSubInterface {\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource jsFunctionInterfaceImpl = new MockJavaResource(
-      "test.MyJsFunctionInterfaceImpl") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("public class MyJsFunctionInterfaceImpl implements MyJsFunctionInterface1 {\n");
-      code.append("public int foo(int x) { return 1; }\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource buggyInterfaceExtendsMultipleInterfaces =
-      new MockJavaResource("test.MyBuggyInterface") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("public interface MyBuggyInterface extends MyJsFunctionInterface1,"
-          + "MyJsFunctionInterface2 {\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource buggyInterfaceBothJsFunctionAndJsType =
-      new MockJavaResource("test.MyBuggyInterface2") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("import com.google.gwt.core.client.js.JsFunction;\n");
-      code.append("import com.google.gwt.core.client.js.JsType;\n");
-      code.append("@JsFunction @JsType public interface MyBuggyInterface2 {\n");
-      code.append("  int foo(int a);");
-      code.append("}\n");
-      return code;
-    }
-  };
-
-  private static final MockJavaResource jsTypeInterface =
-      new MockJavaResource("test.MyJsTypeInterface") {
-    @Override
-    public CharSequence getContent() {
-      StringBuilder code = new StringBuilder();
-      code.append("package test;\n");
-      code.append("import com.google.gwt.core.client.js.JsType;\n");
-      code.append("@JsType public interface MyJsTypeInterface {\n");
-      code.append("}\n");
-      return code;
-    }
-  };
-
   public final void assertBuggySucceeds(String... expectedWarnings)
       throws UnableToCompleteException {
     Result result = assertCompileSucceeds("Buggy buggy = null;", expectedWarnings);
@@ -1064,6 +883,7 @@
   }
 
   public final void assertBuggyFails(String... expectedErrors) {
+    assertTrue(expectedErrors.length > 0);
     assertCompileFails("Buggy buggy = null;", expectedErrors);
   }
 
diff --git a/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java b/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java
index 56a655f..509f32e 100644
--- a/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java
@@ -48,24 +48,15 @@
     assertEquals(12, jsFunctionInterface.foo(10));
   }
 
-  public void testJsFunctionSubInterface_js() {
-    MySubinterfaceOfJsFunctionInterface impl = new MySubinterfaceOfJsFunctionInterface() {
+  public void testJsFunctionViaFunctionMethods() {
+    MyJsFunctionInterface jsFunctionInterface = new MyJsFunctionInterface() {
       @Override
       public int foo(int a) {
-        return a + 3;
+        return a + 2;
       }
     };
-    assertEquals(13, callAsFunction(impl, 10));
-  }
-
-  public void testJsFunctionSubInterface_java() {
-    MySubinterfaceOfJsFunctionInterface impl = new MySubinterfaceOfJsFunctionInterface() {
-        @Override
-      public int foo(int a) {
-        return a + 3;
-      }
-    };
-    assertEquals(13, impl.foo(10));
+    assertEquals(12, callWithFunctionApply(jsFunctionInterface, 10));
+    assertEquals(12, callWithFunctionCall(jsFunctionInterface, 10));
   }
 
   public void testJsFunctionSubImpl_js() {
@@ -78,16 +69,6 @@
     assertEquals(21, impl.foo(10));
   }
 
-  public void testJsFunctionMultipleInheritance_js() {
-    MyJsFunctionMultipleInheritance impl = new MyJsFunctionMultipleInheritance();
-    assertEquals(21, callAsFunction(impl, 10));
-  }
-
-  public void testJsFunctionMultipleInheritance_java() {
-    MyJsFunctionMultipleInheritance impl = new MyJsFunctionMultipleInheritance();
-    assertEquals(21, impl.foo(10));
-  }
-
   public void testJsFunctionIdentity_js() {
     MyJsFunctionIdentityInterface id = new MyJsFunctionIdentityInterface() {
       @Override
@@ -203,15 +184,8 @@
     assertNotNull(c3);
     MyJsFunctionIdentityInterface c4 = (MyJsFunctionIdentityInterface) object;
     assertNotNull(c4);
-
-    // TODO: unexpected behavior. Anything can be cast to a JsType(without prototype).
-    try {
-      ElementLikeJsInterface c5 = (ElementLikeJsInterface) object;
-      assertNotNull(c5);
-      fail("ClassCastException should be caught.");
-    } catch (ClassCastException cce) {
-      // Expected.
-    }
+    ElementLikeJsInterface c5 = (ElementLikeJsInterface) object;
+    assertNotNull(c5);
   }
 
   public void testCast_crossCastJavaInstance() {
@@ -241,8 +215,7 @@
     assertTrue(object instanceof MyJsFunctionInterface);
     assertTrue(object instanceof MyJsFunctionInterfaceImpl);
     assertTrue(object instanceof MyJsFunctionIdentityInterface);
-    // TODO: unexpected behavior. Anything can be instanceof a JsType(without prototype).
-    assertFalse(object instanceof ElementLikeJsInterface);
+    assertTrue(object instanceof ElementLikeJsInterface);
   }
 
   // uncomment when Java8 is supported.
@@ -265,20 +238,20 @@
 //    assertEquals(10, callAsFunction(impl, 10));
 //  }
 
-  public void testJsFunctionAccidentalOverrides() {
-    MyJsFunctionAccidentalOverrideParent p = new MyJsFunctionAccidentalOverrideParent();
-    assertEquals(10, p.foo(10));
-    MyJsFunctionAccidentalOverrideChild c = new MyJsFunctionAccidentalOverrideChild();
-    assertEquals(10, c.foo(10));
-    assertEquals(10, callAsFunction(c, 10));
-  }
-
-  private static native Object callAsFunction(Object obj) /*-{
-    return obj();
+  private static native Object callAsFunction(Object fn) /*-{
+    return fn();
   }-*/;
 
-  private static native int callAsFunction(Object obj, int arg) /*-{
-    return obj(arg);
+  private static native int callAsFunction(Object fn, int arg) /*-{
+    return fn(arg);
+  }-*/;
+
+  private static native int callWithFunctionApply(Object fn, int arg) /*-{
+    return fn.apply(this, [arg]);
+  }-*/;
+
+  private static native int callWithFunctionCall(Object fn, int arg) /*-{
+    return fn.call(this, arg);
   }-*/;
 
   private static native void setField(Object object, String fieldName, int value) /*-{
diff --git a/user/test/com/google/gwt/core/client/interop/MyJsFunctionAccidentalOverrideChild.java b/user/test/com/google/gwt/core/client/interop/MyJsFunctionAccidentalOverrideChild.java
deleted file mode 100644
index 36d37cb..0000000
--- a/user/test/com/google/gwt/core/client/interop/MyJsFunctionAccidentalOverrideChild.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.core.client.interop;
-
-/**
- * A class that inherits public function from its super class which accidentally overrides the SAM
- * function in its super interface.
- */
-public class MyJsFunctionAccidentalOverrideChild extends MyJsFunctionAccidentalOverrideParent
-    implements MyJsFunctionInterface {
-
-}
diff --git a/user/test/com/google/gwt/core/client/interop/MyJsFunctionAccidentalOverrideParent.java b/user/test/com/google/gwt/core/client/interop/MyJsFunctionAccidentalOverrideParent.java
deleted file mode 100644
index 1dd1f64..0000000
--- a/user/test/com/google/gwt/core/client/interop/MyJsFunctionAccidentalOverrideParent.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.core.client.interop;
-
-/**
- * A Java class that has a method with the same signature as the SAM function in
- * {@code MyJsFunctionInterface}.
- */
-public class MyJsFunctionAccidentalOverrideParent {
-
-  public int foo(int a) {
-    return a;
-  }
-}
diff --git a/user/test/com/google/gwt/core/client/interop/MyJsFunctionMultipleInheritance.java b/user/test/com/google/gwt/core/client/interop/MyJsFunctionMultipleInheritance.java
deleted file mode 100644
index a5dafbc..0000000
--- a/user/test/com/google/gwt/core/client/interop/MyJsFunctionMultipleInheritance.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.core.client.interop;
-
-/**
- * A concrete class, whose super super class implements a @JsFunction interface, who itself also
- * implements the same @JsFunction interface, and also implements another interface that has a
- * method with the same signature.
- */
-public class MyJsFunctionMultipleInheritance extends MySubclassOfJsFunctionInterfaceImpl
-  implements MyJsFunctionInterface, PlainInterfaceWithSameMethod {
-
-}
diff --git a/user/test/com/google/gwt/core/client/interop/MySubinterfaceOfJsFunctionInterface.java b/user/test/com/google/gwt/core/client/interop/MySubinterfaceOfJsFunctionInterface.java
deleted file mode 100644
index aae78f4..0000000
--- a/user/test/com/google/gwt/core/client/interop/MySubinterfaceOfJsFunctionInterface.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.core.client.interop;
-
-/**
- * An interface extends a @JsFunction interface.
- */
-public interface MySubinterfaceOfJsFunctionInterface extends MyJsFunctionInterface {
-
-}