diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java index 139f8656cb7b4f..d98c32aa699064 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java @@ -15,7 +15,6 @@ package com.google.devtools.build.lib.analysis.skylark; import com.google.common.base.Preconditions; -import com.google.common.base.Strings; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -246,13 +245,13 @@ public static SkylarkLateBoundDefault forConfigurationFie SkylarkLateBoundDefault resolver = fieldCache.get(cacheKey).get(fragmentFieldName); if (resolver == null) { - String fragmentName = SkylarkModule.Resolver.resolveName(fragmentClass); - if (Strings.isNullOrEmpty(fragmentName)) { + SkylarkModule moduleAnnotation = SkylarkInterfaceUtils.getSkylarkModule(fragmentClass); + if (moduleAnnotation == null) { throw new AssertionError("fragment class must have a valid skylark name"); } throw new InvalidConfigurationFieldException( String.format("invalid configuration field name '%s' on fragment '%s'", - fragmentFieldName, fragmentName)); + fragmentFieldName, moduleAnnotation.name())); } return resolver; } catch (ExecutionException e) { diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkCallable.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkCallable.java index df3387a26a4656..4856601b59e6d4 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkCallable.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkCallable.java @@ -19,10 +19,25 @@ import java.lang.annotation.Target; /** - * A marker interface for Java methods which can be called from Skylark. + * Annotates a Java method that can be called from Skylark. * - *

Methods annotated with this annotation are expected to meet certain requirements which are - * enforced by an annotation processor: + *

This annotation is only allowed to appear on methods of classes that are directly annotated + * with {@link SkylarkModule} or {@link SkylarkGlobalLibrary}. Since subtypes can't add new + * Skylark-accessible methods unless they have their own {@code @SkylarkModule} annotation, this + * implies that you can always determine the complete set of Skylark entry points for a given {@link + * SkylarkValue} type by looking at the ancestor class or interface from which it inherits its + * {@code @SkylarkModule}. + * + *

If a method is annotated with {@code @SkylarkCallable}, it is not allowed to have any + * overloads or hide any static or default methods. Overriding is allowed, but the {@code + * @SkylarkCallable} annotation itself must not be repeated on the override. This ensures that given + * a method, we can always determine its corresponding {@code @SkylarkCallable} annotation, if it + * has one, by scanning all methods of the same name in its class hierarchy, without worrying about + * complications like overloading or generics. The lookup functionality is implemented by {@link + * SkylarkInterfaceUtils#getSkylarkCallable}. + * + *

Methods having this annotation are required to satisfy the following (enforced by an + * annotation processor): * *