bazel packages: delete StructImpl.hasField
Essentially every use is followed by a call to getField,
so it is unnecessary and inefficient to make two calls,
and risks potential inconsistency.
Also delete getValueOrNull.
@VisibleForTesting isn't worth the paper it is printed on.
PiperOrigin-RevId: 284208235
diff --git a/src/main/java/com/google/devtools/build/lib/packages/NativeInfo.java b/src/main/java/com/google/devtools/build/lib/packages/NativeInfo.java
index a05d9b9..867e18a 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/NativeInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/NativeInfo.java
@@ -41,10 +41,14 @@
@Override
public Object getValue(String name) throws EvalException {
+ // Starlark field
Object x = values.get(name);
if (x != null) {
return x;
- } else if (hasField(name)) {
+ }
+
+ // @SkylarkCallable(structField=true) -- Java field
+ if (getFieldNames().contains(name)) {
try {
return CallUtils.getField(SEMANTICS, this, name);
} catch (InterruptedException exception) {
@@ -52,28 +56,32 @@
// exceptions, as they should be logicless field accessors. If this occurs, it's
// indicative of a bad NativeInfo implementation.
throw new IllegalStateException(
- String.format("Access of field %s was unexpectedly interrupted, but should be "
- + "uninterruptible. This is indicative of a bad provider implementation.", name));
+ String.format(
+ "Access of field %s was unexpectedly interrupted, but should be "
+ + "uninterruptible. This is indicative of a bad provider implementation.",
+ name));
}
- } else if (name.equals("to_json") || name.equals("to_proto")) {
- // to_json and to_proto should not be methods of struct or provider instances.
- // However, they are, for now, and it is important that they be consistently
- // returned by attribute lookup operations regardless of whether a field or method
- // is desired. TODO(adonovan): eliminate this hack.
- return new BuiltinCallable(this, name);
- } else {
- return null;
}
- }
- @Override
- public boolean hasField(String name) {
- return getFieldNames().contains(name);
+ // to_json and to_proto should not be methods of struct or provider instances.
+ // However, they are, for now, and it is important that they be consistently
+ // returned by attribute lookup operations regardless of whether a field or method
+ // is desired. TODO(adonovan): eliminate this hack.
+ if (name.equals("to_json") || name.equals("to_proto")) {
+ return new BuiltinCallable(this, name);
+ }
+
+ return null;
}
@Override
public ImmutableCollection<String> getFieldNames() {
if (fieldNames == null) {
+ // TODO(adonovan): the assignment to this.fieldNames is not thread safe!
+ // We cannot assume that build() is a constructor of an object all of
+ // whose fields are final (and thus subject to a write barrier).
+ //
+ // Also, consider using a lazy union of the two underlying sets.
fieldNames =
ImmutableSet.<String>builder()
.addAll(values.keySet())