Fixes to Skylark function call

Allow a call to a struct's field when it's a function.
Check whether a java method exists before issuing KwArg error.

--
MOS_MIGRATED_REVID=101937143
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
index 2e90afd..73e8d10 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java
@@ -355,10 +355,19 @@
   // exactly and copy that behaviour.
   // TODO(bazel-team): check if this and SkylarkBuiltInFunctions.createObject can be merged.
   private Object invokeJavaMethod(
-      Object obj, Class<?> objClass, String methodName, List<Object> args) throws EvalException {
+      Object obj, Class<?> objClass, String methodName, List<Object> args, boolean hasKwArgs)
+      throws EvalException {
     MethodDescriptor matchingMethod = null;
     List<MethodDescriptor> methods = getMethods(objClass, methodName, args.size(), getLocation());
     if (methods != null) {
+      if (hasKwArgs) {
+        throw new EvalException(
+            func.getLocation(),
+            String.format(
+                "Keyword arguments are not allowed when calling a java method"
+                + "\nwhile calling method '%s' on object of type %s",
+                func.getName(), EvalUtils.getDataTypeNameFromClass(objClass)));
+      }
       for (MethodDescriptor method : methods) {
         Class<?>[] params = method.getMethod().getParameterTypes();
         int i = 0;
@@ -508,25 +517,34 @@
       return convertFromSkylark(
           function.call(posargs.build(), ImmutableMap.<String, Object>copyOf(kwargs), this, env),
           env);
+    } else if (objValue instanceof ClassObject) {
+      Object fieldValue = ((ClassObject) objValue).getValue(func.getName());
+      if (fieldValue == null) {
+        throw new EvalException(
+            getLocation(), String.format("struct has no method '%s'", func.getName()));
+      }
+      if (!(fieldValue instanceof BaseFunction)) {
+        throw new EvalException(
+            getLocation(), String.format("struct field '%s' is not a function", func.getName()));
+      }
+      function = (BaseFunction) fieldValue;
+      evalArguments(posargs, kwargs, env, function);
+      return convertFromSkylark(
+          function.call(posargs.build(), ImmutableMap.<String, Object>copyOf(kwargs), this, env),
+          env);
     } else if (env.isSkylark()) {
       // Only allow native Java calls when using Skylark
       // When calling a Java method, the name is not in the Environment,
       // so evaluating 'func' would fail.
       evalArguments(posargs, kwargs, env, null);
-      if (!kwargs.isEmpty()) {
-        throw new EvalException(
-            func.getLocation(),
-            String.format(
-                "Keyword arguments are not allowed when calling a java method"
-                + "\nwhile calling method '%s' on object %s of type %s",
-                func.getName(), objValue, EvalUtils.getDataTypeName(objValue)));
-      }
       if (objValue instanceof Class<?>) {
         // Static Java method call. We can return the value from here directly because
         // invokeJavaMethod() has special checks.
-        return invokeJavaMethod(null, (Class<?>) objValue, func.getName(), posargs.build());
+        return invokeJavaMethod(
+            null, (Class<?>) objValue, func.getName(), posargs.build(), !kwargs.isEmpty());
       } else {
-        return invokeJavaMethod(objValue, objValue.getClass(), func.getName(), posargs.build());
+        return invokeJavaMethod(
+            objValue, objValue.getClass(), func.getName(), posargs.build(), !kwargs.isEmpty());
       }
     } else {
       throw new EvalException(