bazel: rename SkylarkValue

This change moves skylarkinterface.SkylarkValue to syntax.StarlarkValue,
and also skylarkinterface.SkylarkPrinter to syntax.Printer, where its
functionality is merged into the existing class of that name.

This change is entirely mechanical, except for syntax.Printer (naturally),
and MethodLibrary and SkylarkEvaluationTest, which needed a tweak
due the removal of the Printer.debugPrint static method.

All classes related to the representation of values are now in the evaluator package;
skylarkinterface now contains only the annotations.

This is a breaking change for copybara.

BEGIN_PUBLIC
bazel: rename SkylarkValue
END_PUBLIC
PiperOrigin-RevId: 282410278
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BUILD b/src/main/java/com/google/devtools/build/lib/syntax/BUILD
index d8b2146..7180f6c 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BUILD
@@ -130,6 +130,7 @@
         "StarlarkList.java",
         "StarlarkMutable.java",
         "StarlarkThread.java",
+        "StarlarkValue.java",
         "StringModule.java",
         "Tuple.java",
     ],
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java
index aa86f4b..90325f0 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BaseFunction.java
@@ -20,7 +20,6 @@
 import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -356,7 +355,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.append("<function " + getName() + ">");
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinCallable.java b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinCallable.java
index ef5851e..292139a 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinCallable.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinCallable.java
@@ -17,7 +17,6 @@
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
 import com.google.devtools.build.lib.profiler.SilentCloseable;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
@@ -83,7 +82,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.append("<built-in function " + methodName + ">");
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
index 537f8ae..3f9a58f 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
@@ -20,7 +20,6 @@
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
 import com.google.devtools.build.lib.profiler.SilentCloseable;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import com.google.devtools.build.lib.syntax.StarlarkThread.LexicalFrame;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -229,7 +228,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.append("<built-in function " + getName() + ">");
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Depset.java b/src/main/java/com/google/devtools/build/lib/syntax/Depset.java
index aebfc0f..c445a9f 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Depset.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Depset.java
@@ -25,8 +25,6 @@
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import java.util.Collection;
 import java.util.List;
 import javax.annotation.Nullable;
@@ -89,7 +87,7 @@
             + " may interfere with the ordering semantics.")
 @Immutable
 @AutoCodec
-public final class Depset implements SkylarkValue {
+public final class Depset implements StarlarkValue {
   private final SkylarkType contentType;
   private final NestedSet<?> set;
   @Nullable private final ImmutableList<Object> items;
@@ -391,7 +389,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.append("depset(");
     printer.printList(set, "[", ", ", "]", null);
     Order order = getOrder();
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Dict.java b/src/main/java/com/google/devtools/build/lib/syntax/Dict.java
index 31e3c8e..76d957b 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Dict.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Dict.java
@@ -20,7 +20,6 @@
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -420,7 +419,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.printList(entrySet(), "{", ", ", "}", null);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
index 15ce13a..70eed1a 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
@@ -23,7 +23,6 @@
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkInterfaceUtils;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.syntax.Concatable.Concatter;
 import com.google.devtools.build.lib.util.SpellChecker;
 import java.util.Collection;
@@ -132,8 +131,8 @@
    * @return true if the object is known to be a hashable value.
    */
   public static boolean isHashable(Object o) {
-    if (o instanceof SkylarkValue) {
-      return ((SkylarkValue) o).isHashable();
+    if (o instanceof StarlarkValue) {
+      return ((StarlarkValue) o).isHashable();
     }
     return isImmutable(o.getClass());
   }
@@ -146,8 +145,8 @@
    */
   // NB: This is used as the basis for accepting objects in Depset-s.
   public static boolean isImmutable(Object o) {
-    if (o instanceof SkylarkValue) {
-      return ((SkylarkValue) o).isImmutable();
+    if (o instanceof StarlarkValue) {
+      return ((StarlarkValue) o).isImmutable();
     }
     return isImmutable(o.getClass());
   }
@@ -191,14 +190,14 @@
       return c;
     }
     // TODO(bazel-team): We should require all Skylark-addressable values that aren't builtin types
-    // (String/Boolean/Integer) to implement SkylarkValue. We should also require them to have a
+    // (String/Boolean/Integer) to implement StarlarkValue. We should also require them to have a
     // (possibly inherited) @SkylarkModule annotation.
     Class<?> parent = SkylarkInterfaceUtils.getParentWithSkylarkModule(c);
     if (parent != null) {
       return parent;
     }
     Preconditions.checkArgument(
-        SkylarkValue.class.isAssignableFrom(c),
+        StarlarkValue.class.isAssignableFrom(c),
         "%s is not allowed as a Starlark value (getSkylarkType() failed)",
         c);
     return c;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index 3391638..07735fc 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -14,7 +14,6 @@
 
 package com.google.devtools.build.lib.syntax;
 
-import static java.util.stream.Collectors.joining;
 
 import com.google.common.base.Ascii;
 import com.google.common.collect.ImmutableList;
@@ -31,7 +30,6 @@
 import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.syntax.EvalUtils.ComparisonException;
 import com.google.devtools.build.lib.syntax.StarlarkSemantics.FlagIdentifier;
 import java.util.ArrayDeque;
@@ -872,17 +870,23 @@
       extraPositionals = @Param(name = "args", doc = "The objects to print."),
       useLocation = true,
       useStarlarkThread = true)
-  public NoneType print(String sep, Sequence<?> starargs, Location loc, StarlarkThread thread)
+  public NoneType print(String sep, Sequence<?> args, Location loc, StarlarkThread thread)
       throws EvalException {
     try {
-      String msg = starargs.stream().map(Printer::debugPrint).collect(joining(sep));
+      Printer p = Printer.getPrinter();
+      String separator = "";
+      for (Object x : args) {
+        p.append(separator);
+        p.debugPrint(x);
+        separator = sep;
+      }
       // As part of the integration test "skylark_flag_test.sh", if the
       // "--internal_skylark_flag_test_canary" flag is enabled, append an extra marker string to
       // the output.
       if (thread.getSemantics().internalSkylarkFlagTestCanary()) {
-        msg += "<== skylark flag test ==>";
+        p.append("<== skylark flag test ==>");
       }
-      thread.handleEvent(Event.debug(loc, msg));
+      thread.handleEvent(Event.debug(loc, p.toString()));
       return Starlark.NONE;
     } catch (NestedSetDepthException exception) {
       throw new EvalException(
@@ -1210,7 +1214,7 @@
               + "100 % -7  # -5 (unlike in some other languages)\n"
               + "int(\"18\")\n"
               + "</pre>")
-  static final class IntModule implements SkylarkValue {} // (documentation only)
+  static final class IntModule implements StarlarkValue {} // (documentation only)
 
   /** Skylark bool type. */
   @SkylarkModule(
@@ -1222,5 +1226,5 @@
               + "<a href=\"globals.html#False\">False</a>. "
               + "Any value can be converted to a boolean using the "
               + "<a href=\"globals.html#bool\">bool</a> function.")
-  static final class BoolModule implements SkylarkValue {} // (documentation only)
+  static final class BoolModule implements StarlarkValue {} // (documentation only)
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/NoneType.java b/src/main/java/com/google/devtools/build/lib/syntax/NoneType.java
index ed9614d..a5effbe 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/NoneType.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/NoneType.java
@@ -16,13 +16,11 @@
 
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 
 /** The type of the Starlark None value. */
 @SkylarkModule(name = "NoneType", documented = false, doc = "The type of the Starlark None value.")
 @Immutable
-public final class NoneType implements SkylarkValue {
+public final class NoneType implements StarlarkValue {
 
   static final NoneType NONE = new NoneType();
 
@@ -44,7 +42,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.append("None");
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
index 7e4548b..70016c5 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
@@ -15,8 +15,6 @@
 
 import com.google.common.base.Strings;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Formattable;
@@ -28,8 +26,73 @@
 import java.util.UnknownFormatConversionException;
 import javax.annotation.Nullable;
 
-/** (Pretty) Printing of Skylark values */
-public class Printer {
+/** A printer of Starlark values. */
+// TODO(adonovan): merge BasePrinter into Printer and simplify.
+public abstract class Printer {
+
+  /** Append a char to the printer's buffer */
+  public abstract Printer append(char c);
+
+  /** Append a char sequence to the printer's buffer */
+  public abstract Printer append(CharSequence s);
+
+  /**
+   * Prints a list to the printer's buffer. All list items are rendered with {@code repr}.
+   *
+   * @param list the list
+   * @param isTuple if true, uses parentheses, otherwise, uses square brackets. Also one-element
+   *     tuples are rendered with a comma after the element.
+   * @return Printer
+   */
+  public abstract Printer printList(Iterable<?> list, boolean isTuple);
+
+  /**
+   * Prints a list to the printer's buffer. All list items are rendered with {@code repr}.
+   *
+   * @param list the list of objects to repr (each as with repr)
+   * @param before a string to print before the list items, e.g. an opening bracket
+   * @param separator a separator to print between items
+   * @param after a string to print after the list items, e.g. a closing bracket
+   * @param singletonTerminator null or a string to print after the list if it is a singleton. The
+   *     singleton case is notably relied upon in python syntax to distinguish a tuple of size one
+   *     such as ("foo",) from a merely parenthesized object such as ("foo")
+   * @return Printer
+   */
+  public abstract Printer printList(
+      Iterable<?> list,
+      String before,
+      String separator,
+      String after,
+      @Nullable String singletonTerminator);
+
+  /** Renders an object with {@code repr} and append to the printer's buffer. */
+  public abstract Printer repr(Object o);
+
+  /** Renders an object with {@code str} and append to the printer's buffer. */
+  public abstract Printer str(Object o);
+
+  /** Renders an object in the style of {@code print} and append to the printer's buffer. */
+  public abstract Printer debugPrint(Object o);
+
+  /**
+   * Performs Python-style string formatting, as per {@code pattern % tuple}. Limitations: only
+   * {@code %d %s %r %%} are supported.
+   *
+   * @param pattern a format string
+   * @param arguments an array containing positional arguments
+   * @return Printer
+   */
+  public abstract Printer format(String pattern, Object... arguments);
+
+  /**
+   * Performs Python-style string formatting, as per {@code pattern % tuple}. Limitations: only
+   * {@code %d %s %r %%} are supported.
+   *
+   * @param pattern a format string
+   * @param arguments a list containing positional arguments
+   * @return Printer
+   */
+  public abstract Printer formatWithList(String pattern, List<?> arguments);
 
   /**
    * Creates an instance of {@link BasePrinter} that wraps an existing buffer.
@@ -69,13 +132,6 @@
 
   private Printer() {}
 
-  // These static methods proxy to the similar methods of BasePrinter
-
-  /** Format an object with Skylark's {@code debugPrint}. */
-  static String debugPrint(Object x) {
-    return getPrinter().debugPrint(x).toString();
-  }
-
   /**
    * Perform Python-style string formatting, lazily.
    *
@@ -140,7 +196,7 @@
   }
 
   /** Actual class that implements Printer API */
-  public static class BasePrinter implements SkylarkPrinter {
+  public static class BasePrinter extends Printer {
     // Methods of this class should not recurse through static methods of Printer
 
     protected final Appendable buffer;
@@ -189,8 +245,8 @@
      * @return the buffer, in fluent style
      */
     public BasePrinter debugPrint(Object o) {
-      if (o instanceof SkylarkValue) {
-        ((SkylarkValue) o).debugPrint(this);
+      if (o instanceof StarlarkValue) {
+        ((StarlarkValue) o).debugPrint(this);
         return this;
       }
 
@@ -202,11 +258,11 @@
      * quote strings at top level, though strings and other values appearing as elements of other
      * structures are quoted as if by {@code repr}.
      *
-     * <p>Implementations of SkylarkValue may define their own behavior of {@code str}.
+     * <p>Implementations of StarlarkValue may define their own behavior of {@code str}.
      */
     public BasePrinter str(Object o) {
-      if (o instanceof SkylarkValue) {
-        ((SkylarkValue) o).str(this);
+      if (o instanceof StarlarkValue) {
+        ((StarlarkValue) o).str(this);
         return this;
       }
 
@@ -220,7 +276,7 @@
      * Prints the quoted representation of Starlark value {@code o}. The quoted form is often a
      * Starlark expression that evaluates to {@code o}.
      *
-     * <p>Implementations of SkylarkValue may define their own behavior of {@code repr}.
+     * <p>Implementations of StarlarkValue may define their own behavior of {@code repr}.
      *
      * <p>In addition to Starlark values, {@code repr} also prints instances of classes Map, List,
      * Map.Entry, Class, Node, or Location. To avoid nondeterminism, all other values are printed
@@ -233,8 +289,8 @@
         // values such as Locations or ASTs.
         this.append("null");
 
-      } else if (o instanceof SkylarkValue) {
-        ((SkylarkValue) o).repr(this);
+      } else if (o instanceof StarlarkValue) {
+        ((StarlarkValue) o).repr(this);
 
       } else if (o instanceof String) {
         writeString((String) o);
@@ -278,7 +334,7 @@
         // but Starlark code cannot access values of o that would reach here,
         // and native code is already trusted to be deterministic.
         // TODO(adonovan): replace this with a default behavior of this.append(o),
-        // once we require that all @Skylark-annotated classes implement SkylarkValue.
+        // once we require that all @Skylark-annotated classes implement StarlarkValue.
         // (After all, Java code can call String.format, which also calls toString.)
         this.append("<unknown object " + o.getClass().getName() + ">");
       }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/RangeList.java b/src/main/java/com/google/devtools/build/lib/syntax/RangeList.java
index edd38b3..df99790 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/RangeList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/RangeList.java
@@ -20,7 +20,6 @@
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import java.util.AbstractList;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
@@ -164,7 +163,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     if (step == 1) {
       printer.format("range(%d, %d)", start, stop);
     } else {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java b/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
index f50d01e..251bf00 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
@@ -19,8 +19,6 @@
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import java.util.List;
 import java.util.Objects;
 
@@ -42,12 +40,11 @@
  * </pre>
  */
 @SkylarkModule(
-  name = "select",
-  doc = "A selector between configuration-dependent entities.",
-  documented = false
-)
+    name = "select",
+    doc = "A selector between configuration-dependent entities.",
+    documented = false)
 @AutoCodec
-public final class SelectorList implements SkylarkValue {
+public final class SelectorList implements StarlarkValue {
   // TODO(build-team): Selectors are currently split between .packages and .syntax . They should
   // really all be in .packages, but then we'd need to figure out a way how to extend binary
   // operators, which is a non-trivial problem.
@@ -168,7 +165,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.printList(elements, "", " + ", "", null);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java b/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
index c4bd73d..97c5005 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
@@ -18,8 +18,6 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import java.util.Map;
 
 /**
@@ -35,12 +33,11 @@
  * </pre>
  */
 @SkylarkModule(
-  name = "selector",
-  doc = "A selector between configuration-dependent entities.",
-  documented = false
-)
+    name = "selector",
+    doc = "A selector between configuration-dependent entities.",
+    documented = false)
 @AutoCodec
-public final class SelectorValue implements SkylarkValue {
+public final class SelectorValue implements StarlarkValue {
   // TODO(bazel-team): Selectors are currently split between .packages and .syntax . They should
   // really all be in .packages, but then we'd need to figure out a way how to extend binary
   // operators, which is a non-trivial problem.
@@ -77,7 +74,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.format("select(%r)", dictionary);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Sequence.java b/src/main/java/com/google/devtools/build/lib/syntax/Sequence.java
index 9c1ce2b..270e112 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Sequence.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Sequence.java
@@ -18,7 +18,6 @@
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import java.util.Collections;
 import java.util.List;
 import java.util.RandomAccess;
@@ -35,7 +34,7 @@
     documented = false,
     category = SkylarkModuleCategory.BUILTIN,
     doc = "common type of lists and tuples.")
-public interface Sequence<E> extends SkylarkValue, List<E>, RandomAccess, SkylarkIndexable {
+public interface Sequence<E> extends StarlarkValue, List<E>, RandomAccess, SkylarkIndexable {
 
   @Override
   default boolean truth() {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkClassObject.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkClassObject.java
index 64e6fc6..1532afe 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkClassObject.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkClassObject.java
@@ -20,10 +20,10 @@
  * A marker interface for a {@link ClassObject} whose {@link #getValue} always returns a
  * Skylark-friendly value, with no defensive conversion required.
  *
- * <p>An value is Skylark-friendly if its class (or a supertype) implements
- * {@link com.google.devtools.build.lib.skylarkinterface.SkylarkValue},
- * is annotated with {@link com.google.devtools.build.lib.skylarkinterface.SkylarkModule}, or is a
- * Skylark primitive like {@link String}.
+ * <p>An value is Skylark-friendly if its class (or a supertype) implements {@link
+ * com.google.devtools.build.lib.syntax.StarlarkValue}, is annotated with {@link
+ * com.google.devtools.build.lib.skylarkinterface.SkylarkModule}, or is a Skylark primitive like
+ * {@link String}.
  *
  * <p>Ideally, this class should not be needed, and all {@link ClassObject}s should only expose
  * Skylark-friendly values.
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java b/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java
index 338bb6f..4623569 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Starlark.java
@@ -17,8 +17,6 @@
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkInterfaceUtils;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.util.Pair;
 import java.util.List;
 import java.util.Map;
@@ -45,7 +43,7 @@
   public static final Object UNBOUND = new UnboundMarker();
 
   @Immutable
-  private static final class UnboundMarker implements SkylarkValue {
+  private static final class UnboundMarker implements StarlarkValue {
     private UnboundMarker() {}
 
     @Override
@@ -59,7 +57,7 @@
     }
 
     @Override
-    public void repr(SkylarkPrinter printer) {
+    public void repr(Printer printer) {
       printer.append("<unbound>");
     }
   }
@@ -84,7 +82,7 @@
    * StarlarkValue.
    */
   public static boolean valid(Object x) {
-    return x instanceof SkylarkValue
+    return x instanceof StarlarkValue
         || x instanceof String
         || x instanceof Boolean
         || x instanceof Integer;
@@ -131,8 +129,8 @@
   public static boolean truth(Object x) {
     if (x instanceof Boolean) {
       return (Boolean) x;
-    } else if (x instanceof SkylarkValue) {
-      return ((SkylarkValue) x).truth();
+    } else if (x instanceof StarlarkValue) {
+      return ((StarlarkValue) x).truth();
     } else if (x instanceof String) {
       return !((String) x).isEmpty();
     } else if (x instanceof Integer) {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkCallable.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkCallable.java
index 1f74915..b4d488d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkCallable.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkCallable.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.syntax;
 
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
@@ -25,7 +24,7 @@
  * Starlark like a function, including built-in functions and methods, Starlark functions, and
  * application-defined objects (such as rules, aspects, and providers in Bazel).
  */
-public interface StarlarkCallable extends SkylarkValue {
+public interface StarlarkCallable extends StarlarkValue {
 
   /**
    * Call this function with the given arguments.
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFunction.java
index 93f43a7..d79e1b0 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkFunction.java
@@ -18,7 +18,6 @@
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
 import com.google.devtools.build.lib.profiler.SilentCloseable;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import com.google.devtools.build.lib.syntax.StarlarkThread.LexicalFrame;
 
 /** A StarlarkFunction is the function value created by a Starlark {@code def} statement. */
@@ -98,7 +97,7 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     Object label = this.definitionGlobals.getLabel();
 
     printer.append("<function " + getName());
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkList.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkList.java
index 411de33..dd150c2 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkList.java
@@ -21,7 +21,6 @@
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import java.util.AbstractList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -187,11 +186,11 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
+  public void repr(Printer printer) {
     printer.printList(this, /*isTuple=*/ false);
   }
 
-  // TODO(adonovan): SkylarkValue has 3 String methods yet still we need this fourth. Why?
+  // TODO(adonovan): StarlarkValue has 3 String methods yet still we need this fourth. Why?
   @Override
   public String toString() {
     return Starlark.repr(this);
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkMutable.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkMutable.java
index f5eb613..ae3da07 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkMutable.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkMutable.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.syntax;
 
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.syntax.Mutability.Freezable;
 import com.google.devtools.build.lib.syntax.Mutability.MutabilityException;
 
@@ -24,7 +23,7 @@
  * {@link Mutability}.
  */
 // TODO(adonovan): merge with Freezable once StarlarkThread and Frame no longer implement Freezable.
-public interface StarlarkMutable extends Freezable, SkylarkValue {
+public interface StarlarkMutable extends Freezable, StarlarkValue {
 
   /**
    * Throws an exception if this object is not mutable.
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkThread.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkThread.java
index 3731194..8913ade 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkThread.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkThread.java
@@ -25,7 +25,6 @@
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.syntax.Mutability.Freezable;
 import com.google.devtools.build.lib.syntax.Mutability.MutabilityException;
 import com.google.devtools.build.lib.util.Fingerprint;
@@ -382,8 +381,8 @@
     private static boolean skylarkObjectsProbablyEqual(Object obj1, Object obj2) {
       // TODO(b/76154791): check this more carefully.
       return obj1.equals(obj2)
-          || (obj1 instanceof SkylarkValue
-              && obj2 instanceof SkylarkValue
+          || (obj1 instanceof StarlarkValue
+              && obj2 instanceof StarlarkValue
               && Starlark.repr(obj1).equals(Starlark.repr(obj2)));
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkValue.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkValue.java
new file mode 100644
index 0000000..2157f09
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkValue.java
@@ -0,0 +1,91 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// 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.devtools.build.lib.syntax;
+
+import com.google.devtools.build.lib.concurrent.ThreadSafety;
+
+/** Base interface for all Starlark values besides boxed Java primitives. */
+public interface StarlarkValue {
+
+  /**
+   * Prints an official representation of object x.
+   *
+   * <p>Convention is that the string should be parseable back to the value x. If this isn't
+   * feasible then it should be a short human-readable description enclosed in angled brackets, e.g.
+   * {@code "<foo object>"}.
+   *
+   * @param printer a printer to be used for formatting nested values.
+   */
+  default void repr(Printer printer) {
+    printer.append("<unknown object ").append(getClass().getName()).append(">");
+  }
+
+  /**
+   * Prints an informal, human-readable representation of the value.
+   *
+   * <p>By default dispatches to the {@code repr} method.
+   *
+   * @param printer a printer to be used for formatting nested values.
+   */
+  default void str(Printer printer) {
+    repr(printer);
+  }
+
+  /**
+   * Prints an informal debug representation of the value.
+   *
+   * <p>This debug representation is only ever printed to the terminal or to another out-of-band
+   * channel, and is never accessible to Skylark code. Therefore, it is safe for the debug
+   * representation to reveal properties of the value that are usually hidden for the sake of
+   * performance, determinism, or forward-compatibility.
+   *
+   * <p>By default dispatches to the {@code str} method.
+   *
+   * @param printer a printer to be used for formatting nested values.
+   */
+  default void debugPrint(Printer printer) {
+    str(printer);
+  }
+
+  /** Returns the truth-value of this Starlark value. */
+  default boolean truth() {
+    return true;
+  }
+
+  /**
+   * Returns if the value is immutable.
+   *
+   * <p>Immutability is deep, i.e. in order for a value to be immutable, all values it is composed
+   * of must be immutable, too.
+   */
+  // TODO(adonovan): eliminate this concept. All uses really need to know is, is it hashable?,
+  // because Starlark values must have stable hashes: a hashable value must either be immutable or
+  // its hash must be part of its identity.
+  // But this must wait until --incompatible_disallow_hashing_frozen_mutables=true is removed.
+  // (see github.com/bazelbuild/bazel/issues/7800)
+  default boolean isImmutable() {
+    // TODO(adonovan): this is an abuse of an unrelated annotation.
+    return getClass().isAnnotationPresent(ThreadSafety.Immutable.class);
+  }
+
+  /**
+   * Returns if the value is hashable and thus suitable for being used as a dictionary key.
+   *
+   * <p>Hashability implies immutability, but not vice versa.
+   */
+  default boolean isHashable() {
+    return this.isImmutable();
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StringModule.java b/src/main/java/com/google/devtools/build/lib/syntax/StringModule.java
index d769c70..e593cda 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StringModule.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StringModule.java
@@ -24,7 +24,6 @@
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -64,7 +63,7 @@
             + "Implicit concatenation of strings is not allowed; use the <code>+</code> "
             + "operator instead. Comparison operators perform a lexicographical comparison; "
             + "use <code>==</code> to test for equality.")
-final class StringModule implements SkylarkValue {
+final class StringModule implements StarlarkValue {
 
   static final StringModule INSTANCE = new StringModule();
 
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Tuple.java b/src/main/java/com/google/devtools/build/lib/syntax/Tuple.java
index b0bad85..0462835 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Tuple.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Tuple.java
@@ -20,7 +20,6 @@
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import java.util.AbstractCollection;
 import java.util.AbstractList;
 import java.util.Arrays;
@@ -163,13 +162,13 @@
   }
 
   @Override
-  public void repr(SkylarkPrinter printer) {
-    // TODO(adonovan): when SkylarkPrinter moves into this package,
+  public void repr(Printer printer) {
+    // TODO(adonovan): when Printer moves into this package,
     // inline and simplify this, the sole call with isTuple=true.
     printer.printList(this, /*isTuple=*/ true);
   }
 
-  // TODO(adonovan): SkylarkValue has 3 String methods yet still we need this fourth. Why?
+  // TODO(adonovan): StarlarkValue has 3 String methods yet still we need this fourth. Why?
   @Override
   public String toString() {
     return Starlark.repr(this);