Enable SkylarkCallable methods to be used on ClassObjects.
Previously, ClassObjects' SkylarkCallable struct fields worked
as expected (with values of the struct taking precedence), but
calling methods annotated with SkylarkCallable did not work at
all; methods were treated as if they were not present in the struct.
This adds some tests for the various ways of looking up fields
and methods, and rearranges the logic in FuncallExpression to
allow for callable methods on SkylarkClassObject's descendants.
--
PiperOrigin-RevId: 150876181
MOS_MIGRATED_REVID=150876181
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 c301061..2c7a2c8 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
@@ -370,7 +370,10 @@
}
if (matchingMethod == null) {
String errorMessage;
- if (argumentListConversionResult == null || argumentListConversionResult.getError() == null) {
+ if (ClassObject.class.isAssignableFrom(objClass)) {
+ errorMessage = String.format("struct has no method '%s'", methodName);
+ } else if (argumentListConversionResult == null
+ || argumentListConversionResult.getError() == null) {
errorMessage =
String.format(
"type '%s' has no method %s",
@@ -606,6 +609,8 @@
Object value = positionals.get(0);
ImmutableList<Object> positionalArgs = positionals.subList(1, positionals.size());
BaseFunction function = Runtime.getFunction(EvalUtils.getSkylarkType(value.getClass()), method);
+ Object fieldValue =
+ (value instanceof ClassObject) ? ((ClassObject) value).getValue(method) : null;
if (function != null) {
if (!isNamespace(value.getClass())) {
// Use self as an implicit parameter in front.
@@ -613,11 +618,7 @@
}
return function.call(
positionalArgs, ImmutableMap.<String, Object>copyOf(keyWordArgs), call, env);
- } else if (value instanceof ClassObject) {
- Object fieldValue = ((ClassObject) value).getValue(method);
- if (fieldValue == null) {
- throw new EvalException(location, String.format("struct has no method '%s'", method));
- }
+ } else if (fieldValue != null) {
if (!(fieldValue instanceof BaseFunction)) {
throw new EvalException(
location, String.format("struct field '%s' is not a function", method));