bazel syntax: move Selector{List,Value} into lib.packages

(Second attempt at commit e8d482496f705304d21c938ec44dc578997ae942, rolled back in commit ed7d241f10c5ebbb7243a86479d2157b5d012b19,
because it broke Skydoc tests. The only new code is in SkydocMain.)

The Bazel 'select' function is no longer in Starlark.UNIVERSE.
It is pre-declared in all Bazel file environments (BUILD, .bzl, WORKSPACE).
This is a new category (though depset belongs in it too),
exposed as StarlarkLibrary.COMMON.

Also:
- make various methods private
- improve the annotation doc comment
- remove legacyNamed for select(x={...}).
  There are no uses in Google's depot.

A later change will merge Selector{List,Value} into a single data
type that represents a node in a binary tree whose branch nodes
are deferred '+' operations and whose leaves are dictionaries.
While removing what looked like unnecessarily qualified class
names, I discovered that BuildType.SelectorList is yet a third (!)
Starlark value class representing the same concept.

PiperOrigin-RevId: 291982062
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java
index 35b05a8..b6b72d6 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.analysis.DefaultInfo;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
 import com.google.devtools.build.lib.packages.SkylarkNativeModule;
+import com.google.devtools.build.lib.packages.StarlarkLibrary;
 import com.google.devtools.build.lib.packages.StructProvider;
 import com.google.devtools.build.lib.skylarkbuildapi.TopLevelBootstrap;
 import com.google.devtools.build.lib.syntax.Starlark;
@@ -42,12 +43,14 @@
           OutputGroupInfo.SKYLARK_CONSTRUCTOR,
           ActionsProvider.INSTANCE,
           DefaultInfo.PROVIDER);
+
   /**
    * Adds bindings for skylark built-ins and non-rules-specific globals of the build API to the
    * given environment map builder.
    */
   public static void addSkylarkGlobalsToBuilder(ImmutableMap.Builder<String, Object> env) {
     env.putAll(Starlark.UNIVERSE);
+    env.putAll(StarlarkLibrary.COMMON); // e.g. select, depset
     topLevelBootstrap.addBindingsToBuilder(env);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/BuildType.java b/src/main/java/com/google/devtools/build/lib/packages/BuildType.java
index 41cb040..65fafb6 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/BuildType.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/BuildType.java
@@ -32,7 +32,6 @@
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Printer;
 import com.google.devtools.build.lib.syntax.Printer.BasePrinter;
-import com.google.devtools.build.lib.syntax.SelectorValue;
 import com.google.devtools.build.lib.syntax.Starlark;
 import com.google.devtools.build.lib.syntax.StarlarkValue;
 import java.util.ArrayList;
@@ -145,9 +144,9 @@
   public static <T> Object selectableConvert(
       Type<T> type, Object x, Object what, LabelConversionContext context)
       throws ConversionException {
-    if (x instanceof com.google.devtools.build.lib.syntax.SelectorList) {
+    if (x instanceof com.google.devtools.build.lib.packages.SelectorList) {
       return new SelectorList<T>(
-          ((com.google.devtools.build.lib.syntax.SelectorList) x).getElements(),
+          ((com.google.devtools.build.lib.packages.SelectorList) x).getElements(),
           what,
           context,
           type);
@@ -493,6 +492,8 @@
    * rawValue + select(...) + select(...) + ..."} syntax. For consistency's sake, raw values are
    * stored as selects with only a default condition.
    */
+  // TODO(adonovan): merge with packages.Selector{List,Value}.
+  // We don't need three classes for the same concept.
   public static final class SelectorList<T> implements StarlarkValue {
     private final Type<T> originalType;
     private final List<Selector<T>> elements;
@@ -570,7 +571,7 @@
         selectorValueList.add(new SelectorValue(element.getEntries(), element.getNoMatchError()));
       }
       try {
-        printer.repr(com.google.devtools.build.lib.syntax.SelectorList.of(selectorValueList));
+        printer.repr(com.google.devtools.build.lib.packages.SelectorList.of(selectorValueList));
       } catch (EvalException e) {
         throw new IllegalStateException("this list should have been validated on creation");
       }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
index 598c33f..a19ba89 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -875,7 +875,7 @@
 
   private void populateEnvironment(ImmutableMap.Builder<String, Object> env) {
     env.putAll(Starlark.UNIVERSE);
-    env.putAll(StarlarkBuildLibrary.BINDINGS);
+    env.putAll(StarlarkLibrary.BUILD); // e.g. rule, select, depset
     env.putAll(SkylarkNativeModule.BINDINGS_FOR_BUILD_FILES);
     env.put("package", newPackageFunction(packageArguments));
     env.putAll(ruleFunctions);
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java b/src/main/java/com/google/devtools/build/lib/packages/SelectorList.java
similarity index 75%
rename from src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
rename to src/main/java/com/google/devtools/build/lib/packages/SelectorList.java
index 1eaf964..7e0799d 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SelectorList.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SelectorList.java
@@ -11,13 +11,21 @@
 // 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;
+package com.google.devtools.build.lib.packages;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 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.syntax.Dict;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.HasBinary;
+import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.SkylarkType;
+import com.google.devtools.build.lib.syntax.Starlark;
+import com.google.devtools.build.lib.syntax.StarlarkValue;
+import com.google.devtools.build.lib.syntax.TokenKind;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -46,8 +54,8 @@
 @AutoCodec
 public final class SelectorList implements StarlarkValue, HasBinary {
 
-  // TODO(adonovan): move to lib.packages.
-  // TODO(adonovan): combine Selector{List,Value}. There's no need for two data types.
+  // TODO(adonovan): combine Selector{List,Value} and BuildType.SelectorList.
+  // We don't need three classes for the same concept
 
   private final Class<?> type;
   private final List<Object> elements;
@@ -62,17 +70,33 @@
    * Returns an ordered list of the elements in this expression. Each element may be a native type
    * or a select.
    */
-  public List<Object> getElements() {
+  List<Object> getElements() {
     return elements;
   }
 
   /** Returns the native type contained by this expression. */
-  public Class<?> getType() {
+  Class<?> getType() {
     return type;
   }
 
+  /** Implementation of the Starlark {@code select} function exposed to BUILD and .bzl files. */
+  public static Object select(Dict<?, ?> dict, String noMatchError) throws EvalException {
+    if (dict.isEmpty()) {
+      throw Starlark.errorf(
+          "select({}) with an empty dictionary can never resolve because it includes no conditions"
+              + " to match");
+    }
+    for (Object key : dict.keySet()) {
+      if (!(key instanceof String)) {
+        throw Starlark.errorf(
+            "select: got %s for dict key, want a label string", Starlark.type(key));
+      }
+    }
+    return SelectorList.of(new SelectorValue(dict, noMatchError));
+  }
+
   /** Creates a "wrapper" list that consists of a single select. */
-  public static SelectorList of(SelectorValue selector) {
+  static SelectorList of(SelectorValue selector) {
     return new SelectorList(selector.getType(), ImmutableList.of(selector));
   }
 
@@ -82,7 +106,7 @@
    *
    * @throws EvalException if the values don't have the same underlying type
    */
-  public static SelectorList concat(Object x, Object y) throws EvalException {
+  static SelectorList concat(Object x, Object y) throws EvalException {
     return of(Arrays.asList(x, y));
   }
 
@@ -100,7 +124,7 @@
    *
    * @throws EvalException if all values don't have the same underlying type
    */
-  public static SelectorList of(Iterable<?> values) throws EvalException {
+  static SelectorList of(Iterable<?> values) throws EvalException {
     Preconditions.checkArgument(!Iterables.isEmpty(values));
     ImmutableList.Builder<Object> elements = ImmutableList.builder();
     Object firstValue = null;
@@ -128,9 +152,9 @@
 
   private static String getTypeName(Object x) {
     if (x instanceof SelectorList) {
-      return "select of " + EvalUtils.getDataTypeNameFromClass(((SelectorList) x).getType());
+      return "select of " + SkylarkType.of(((SelectorList) x).getType());
     } else if (x instanceof SelectorValue) {
-      return "select of " + EvalUtils.getDataTypeNameFromClass(((SelectorValue) x).getType());
+      return "select of " + SkylarkType.of(((SelectorValue) x).getType());
     } else {
       return Starlark.type(x);
     }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java b/src/main/java/com/google/devtools/build/lib/packages/SelectorValue.java
similarity index 68%
rename from src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
rename to src/main/java/com/google/devtools/build/lib/packages/SelectorValue.java
index 8122b9a..e61d6e8 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SelectorValue.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SelectorValue.java
@@ -11,17 +11,23 @@
 // 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;
+package com.google.devtools.build.lib.packages;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 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.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.HasBinary;
+import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.Starlark;
+import com.google.devtools.build.lib.syntax.StarlarkValue;
+import com.google.devtools.build.lib.syntax.TokenKind;
 import java.util.Map;
 
 /**
- * The value passed to a select({...}) statement, e.g.:
+ * The value returned by a call to {@code select({...})}, for example:
  *
  * <pre>
  *   rule(
@@ -34,29 +40,31 @@
  */
 @SkylarkModule(
     name = "selector",
-    doc = "A selector between configuration-dependent entities.",
+    doc = "A selector between configuration-dependent values.",
     documented = false)
 @AutoCodec
 public final class SelectorValue implements StarlarkValue, HasBinary {
 
-  // TODO(adonovan): move to lib.packages.
-  // TODO(adonovan): combine Selector{List,Value}. There's no need for two data types.
+  // TODO(adonovan): combine Selector{List,Value} and BuildType.SelectorList.
+  // We don't need three classes for the same concept.
 
   private final ImmutableMap<?, ?> dictionary;
   private final Class<?> type;
   private final String noMatchError;
 
-  public SelectorValue(Map<?, ?> dictionary, String noMatchError) {
+  SelectorValue(Map<?, ?> dictionary, String noMatchError) {
     Preconditions.checkArgument(!dictionary.isEmpty());
     this.dictionary = ImmutableMap.copyOf(dictionary);
-    this.type = Iterables.get(dictionary.values(), 0).getClass();
+    // TODO(adonovan): doesn't this assume all the elements have the same type?
+    this.type = Iterables.getFirst(dictionary.values(), null).getClass();
     this.noMatchError = noMatchError;
   }
 
-  public ImmutableMap<?, ?> getDictionary() {
+  ImmutableMap<?, ?> getDictionary() {
     return dictionary;
   }
 
+  // TODO(adonovan): use SkylarkType not Class, like Depset.
   Class<?> getType() {
     return type;
   }
@@ -65,7 +73,7 @@
    * Returns a custom error message for this select when no condition matches, or an empty string if
    * no such message is declared.
    */
-  public String getNoMatchError() {
+  String getNoMatchError() {
     return noMatchError;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
index c35e3c8..fd9664c 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
@@ -399,7 +399,7 @@
       // Even though this is clearly imperfect, we return this value because otherwise
       // native.rules() fails if there is any rule using a select() in the BUILD file.
       //
-      // To remedy this, we should return a syntax.SelectorList. To do so, we have to
+      // To remedy this, we should return a SelectorList. To do so, we have to
       // 1) recurse into the Selector contents of SelectorList, so those values are skylarkified too
       // 2) get the right Class<?> value. We could probably get at that by looking at
       //    ((SelectorList)val).getSelectors().first().getEntries().first().getClass().
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkBuildLibrary.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkBuildLibrary.java
deleted file mode 100644
index ce9afaf..0000000
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkBuildLibrary.java
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2019 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.packages;
-
-import static com.google.devtools.build.lib.packages.PackageFactory.getContext;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
-import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.packages.License.DistributionType;
-import com.google.devtools.build.lib.packages.PackageFactory.PackageContext;
-import com.google.devtools.build.lib.packages.Type.ConversionException;
-import com.google.devtools.build.lib.skylarkinterface.Param;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary;
-import com.google.devtools.build.lib.syntax.EvalException;
-import com.google.devtools.build.lib.syntax.NoneType;
-import com.google.devtools.build.lib.syntax.Sequence;
-import com.google.devtools.build.lib.syntax.Starlark;
-import com.google.devtools.build.lib.syntax.StarlarkThread;
-import java.util.List;
-import java.util.Set;
-
-/** A global library of Starlark functions which are available only when evaluating BUILD files. */
-@SkylarkGlobalLibrary
-class StarlarkBuildLibrary {
-
-  /**
-   * Map of Starlark values (keyed by their symbol name) defined by this global library for use in
-   * the global Starlark environment for BUILD files.
-   */
-  public static final ImmutableMap<String, Object> BINDINGS = initializeBindings();
-
-  private static ImmutableMap<String, Object> initializeBindings() {
-    ImmutableMap.Builder<String, Object> env = ImmutableMap.builder();
-    Starlark.addMethods(env, new StarlarkBuildLibrary());
-    return env.build();
-  }
-
-  private StarlarkBuildLibrary() {
-    // Not instantiable outside this class.
-  }
-
-  @SkylarkCallable(
-      name = "environment_group",
-      doc =
-          "Defines a set of related environments that can be tagged onto rules to prevent"
-              + "incompatible rules from depending on each other.",
-      parameters = {
-        @Param(
-            name = "name",
-            type = String.class,
-            positional = false,
-            named = true,
-            doc = "The name of the rule."),
-        // Both parameter below are lists of label designators
-        @Param(
-            name = "environments",
-            type = Sequence.class,
-            generic1 = Object.class,
-            positional = false,
-            named = true,
-            doc = "A list of Labels for the environments to be grouped, from the same package."),
-        @Param(
-            name = "defaults",
-            type = Sequence.class,
-            generic1 = Object.class,
-            positional = false,
-            named = true,
-            doc = "A list of Labels.")
-      }, // TODO(bazel-team): document what that is
-      // Not documented by docgen, as this is only available in BUILD files.
-      // TODO(cparsons): Devise a solution to document BUILD functions.
-      documented = false,
-      useStarlarkThread = true)
-  public NoneType environmentGroup(
-      String name,
-      Sequence<?> environmentsList, // <Label>
-      Sequence<?> defaultsList, // <Label>
-      StarlarkThread thread)
-      throws EvalException {
-    PackageContext context = getContext(thread);
-    List<Label> environments =
-        BuildType.LABEL_LIST.convert(
-            environmentsList,
-            "'environment_group argument'",
-            context.pkgBuilder.getBuildFileLabel());
-    List<Label> defaults =
-        BuildType.LABEL_LIST.convert(
-            defaultsList, "'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
-
-    if (environments.isEmpty()) {
-      throw Starlark.errorf("environment group %s must contain at least one environment", name);
-    }
-    try {
-      Location loc = thread.getCallerLocation();
-      context.pkgBuilder.addEnvironmentGroup(
-          name, environments, defaults, context.eventHandler, loc);
-      return Starlark.NONE;
-    } catch (LabelSyntaxException e) {
-      throw Starlark.errorf("environment group has invalid name: %s: %s", name, e.getMessage());
-    } catch (Package.NameConflictException e) {
-      throw Starlark.errorf("%s", e.getMessage());
-    }
-  }
-
-  @SkylarkCallable(
-      name = "licenses",
-      doc = "Declare the license(s) for the code in the current package.",
-      parameters = {
-        @Param(
-            name = "license_strings",
-            type = Sequence.class,
-            generic1 = String.class,
-            doc = "A list of strings, the names of the licenses used.")
-      },
-      // Not documented by docgen, as this is only available in BUILD files.
-      // TODO(cparsons): Devise a solution to document BUILD functions.
-      documented = false,
-      useStarlarkThread = true)
-  public NoneType licenses(
-      Sequence<?> licensesList, // list of license strings
-      StarlarkThread thread)
-      throws EvalException {
-    PackageContext context = getContext(thread);
-    try {
-      License license = BuildType.LICENSE.convert(licensesList, "'licenses' operand");
-      context.pkgBuilder.setDefaultLicense(license);
-    } catch (ConversionException e) {
-      context.eventHandler.handle(Event.error(thread.getCallerLocation(), e.getMessage()));
-      context.pkgBuilder.setContainsErrors();
-    }
-    return Starlark.NONE;
-  }
-
-  @SkylarkCallable(
-      name = "distribs",
-      doc = "Declare the distribution(s) for the code in the current package.",
-      parameters = {
-        @Param(name = "distribution_strings", type = Object.class, doc = "The distributions.")
-      },
-      // Not documented by docgen, as this is only available in BUILD files.
-      // TODO(cparsons): Devise a solution to document BUILD functions.
-      documented = false,
-      useStarlarkThread = true)
-  public NoneType distribs(Object object, StarlarkThread thread) throws EvalException {
-    PackageContext context = getContext(thread);
-
-    try {
-      Set<DistributionType> distribs =
-          BuildType.DISTRIBUTIONS.convert(object, "'distribs' operand");
-      context.pkgBuilder.setDefaultDistribs(distribs);
-    } catch (ConversionException e) {
-      context.eventHandler.handle(Event.error(thread.getCallerLocation(), e.getMessage()));
-      context.pkgBuilder.setContainsErrors();
-    }
-    return Starlark.NONE;
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java
new file mode 100644
index 0000000..a943f94
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java
@@ -0,0 +1,226 @@
+// Copyright 2019 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.packages;
+
+import static com.google.devtools.build.lib.packages.PackageFactory.getContext;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.License.DistributionType;
+import com.google.devtools.build.lib.packages.PackageFactory.PackageContext;
+import com.google.devtools.build.lib.packages.Type.ConversionException;
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary;
+import com.google.devtools.build.lib.syntax.Dict;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.NoneType;
+import com.google.devtools.build.lib.syntax.Sequence;
+import com.google.devtools.build.lib.syntax.Starlark;
+import com.google.devtools.build.lib.syntax.StarlarkThread;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A library of pre-declared Bazel Starlark functions.
+ *
+ * <p>For functions pre-declared in a BUILD file, use {@link #BUILD}. For Bazel functions such as
+ * {@code select} and {@code depset} that are pre-declared in all BUILD, .bzl, and WORKSPACE files,
+ * use {@link #COMMON}. For functions pre-declared in every Starlark file, use {@link
+ * Starlark#UNIVERSE}.
+ */
+public final class StarlarkLibrary {
+
+  private StarlarkLibrary() {} // uninstantiable
+
+  /**
+   * A library of Starlark functions (keyed by name) that are not part of core Starlark but are
+   * common to all Bazel Starlark file environments (BUILD, .bzl, and WORKSPACE). Examples: depset,
+   * select.
+   */
+  public static final ImmutableMap<String, Object> COMMON = initCommon();
+
+  private static ImmutableMap<String, Object> initCommon() {
+    ImmutableMap.Builder<String, Object> env = ImmutableMap.builder();
+    Starlark.addMethods(env, new CommonLibrary());
+    return env.build();
+  }
+
+  @SkylarkGlobalLibrary
+  private static class CommonLibrary {
+    @SkylarkCallable(
+        name = "select",
+        doc =
+            "<code>select()</code> is the helper function that makes a rule attribute "
+                + "<a href=\"$BE_ROOT/common-definitions.html#configurable-attributes\">"
+                + "configurable</a>. See "
+                + "<a href=\"$BE_ROOT/functions.html#select\">build encyclopedia</a> for details.",
+        parameters = {
+          @Param(
+              name = "x",
+              type = Dict.class,
+              positional = true,
+              doc =
+                  "A dict that maps configuration conditions to values. Each key is a label string"
+                      + " that identifies a config_setting instance."),
+          @Param(
+              name = "no_match_error",
+              type = String.class,
+              defaultValue = "''",
+              doc = "Optional custom error to report if no condition matches.",
+              named = true),
+        })
+    public Object select(Dict<?, ?> dict, String noMatchError) throws EvalException {
+      return SelectorList.select(dict, noMatchError);
+    }
+
+    // TODO(adonovan): move depset here.
+  }
+
+  /**
+   * A library of Starlark functions (keyed by name) pre-declared in BUILD files. A superset of
+   * {@link #COMMON} (e.g. select). Excludes functions in the native module, such as exports_files.
+   * Examples: environment_group, select.
+   */
+  public static final ImmutableMap<String, Object> BUILD = initBUILD();
+
+  private static ImmutableMap<String, Object> initBUILD() {
+    ImmutableMap.Builder<String, Object> env = ImmutableMap.builder();
+    Starlark.addMethods(env, new BuildLibrary());
+    env.putAll(COMMON);
+    return env.build();
+  }
+
+  @SkylarkGlobalLibrary
+  private static class BuildLibrary {
+    @SkylarkCallable(
+        name = "environment_group",
+        doc =
+            "Defines a set of related environments that can be tagged onto rules to prevent"
+                + "incompatible rules from depending on each other.",
+        parameters = {
+          @Param(
+              name = "name",
+              type = String.class,
+              positional = false,
+              named = true,
+              doc = "The name of the rule."),
+          // Both parameter below are lists of label designators
+          @Param(
+              name = "environments",
+              type = Sequence.class,
+              generic1 = Object.class,
+              positional = false,
+              named = true,
+              doc = "A list of Labels for the environments to be grouped, from the same package."),
+          @Param(
+              name = "defaults",
+              type = Sequence.class,
+              generic1 = Object.class,
+              positional = false,
+              named = true,
+              doc = "A list of Labels.")
+        }, // TODO(bazel-team): document what that is
+        // Not documented by docgen, as this is only available in BUILD files.
+        // TODO(cparsons): Devise a solution to document BUILD functions.
+        documented = false,
+        useStarlarkThread = true)
+    public NoneType environmentGroup(
+        String name,
+        Sequence<?> environmentsList, // <Label>
+        Sequence<?> defaultsList, // <Label>
+        StarlarkThread thread)
+        throws EvalException {
+      PackageContext context = getContext(thread);
+      List<Label> environments =
+          BuildType.LABEL_LIST.convert(
+              environmentsList,
+              "'environment_group argument'",
+              context.pkgBuilder.getBuildFileLabel());
+      List<Label> defaults =
+          BuildType.LABEL_LIST.convert(
+              defaultsList, "'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
+
+      if (environments.isEmpty()) {
+        throw Starlark.errorf("environment group %s must contain at least one environment", name);
+      }
+      try {
+        Location loc = thread.getCallerLocation();
+        context.pkgBuilder.addEnvironmentGroup(
+            name, environments, defaults, context.eventHandler, loc);
+        return Starlark.NONE;
+      } catch (LabelSyntaxException e) {
+        throw Starlark.errorf("environment group has invalid name: %s: %s", name, e.getMessage());
+      } catch (Package.NameConflictException e) {
+        throw Starlark.errorf("%s", e.getMessage());
+      }
+    }
+
+    @SkylarkCallable(
+        name = "licenses",
+        doc = "Declare the license(s) for the code in the current package.",
+        parameters = {
+          @Param(
+              name = "license_strings",
+              type = Sequence.class,
+              generic1 = String.class,
+              doc = "A list of strings, the names of the licenses used.")
+        },
+        // Not documented by docgen, as this is only available in BUILD files.
+        // TODO(cparsons): Devise a solution to document BUILD functions.
+        documented = false,
+        useStarlarkThread = true)
+    public NoneType licenses(
+        Sequence<?> licensesList, // list of license strings
+        StarlarkThread thread)
+        throws EvalException {
+      PackageContext context = getContext(thread);
+      try {
+        License license = BuildType.LICENSE.convert(licensesList, "'licenses' operand");
+        context.pkgBuilder.setDefaultLicense(license);
+      } catch (ConversionException e) {
+        context.eventHandler.handle(Event.error(thread.getCallerLocation(), e.getMessage()));
+        context.pkgBuilder.setContainsErrors();
+      }
+      return Starlark.NONE;
+    }
+
+    @SkylarkCallable(
+        name = "distribs",
+        doc = "Declare the distribution(s) for the code in the current package.",
+        parameters = {
+          @Param(name = "distribution_strings", type = Object.class, doc = "The distributions.")
+        },
+        // Not documented by docgen, as this is only available in BUILD files.
+        // TODO(cparsons): Devise a solution to document BUILD functions.
+        documented = false,
+        useStarlarkThread = true)
+    public NoneType distribs(Object object, StarlarkThread thread) throws EvalException {
+      PackageContext context = getContext(thread);
+
+      try {
+        Set<DistributionType> distribs =
+            BuildType.DISTRIBUTIONS.convert(object, "'distribs' operand");
+        context.pkgBuilder.setDefaultDistribs(distribs);
+      } catch (ConversionException e) {
+        context.eventHandler.handle(Event.error(thread.getCallerLocation(), e.getMessage()));
+        context.pkgBuilder.setContainsErrors();
+      }
+      return Starlark.NONE;
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
index f59f28e..b3cc560 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
@@ -349,6 +349,7 @@
   private ImmutableMap<String, Object> getDefaultEnvironment() {
     ImmutableMap.Builder<String, Object> env = ImmutableMap.builder();
     env.putAll(Starlark.UNIVERSE);
+    env.putAll(StarlarkLibrary.COMMON); // e.g. select, depset
     env.putAll(workspaceFunctions);
     if (installDir != null) {
       env.put("__embedded_dir__", installDir.getPathString());
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 f857248..c5c9413 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BUILD
@@ -113,8 +113,6 @@
         "ParamDescriptor.java",
         "Printer.java",
         "RangeList.java",
-        "SelectorList.java",
-        "SelectorValue.java",
         "Sequence.java",
         "SkylarkClassObject.java",
         "SkylarkIndexable.java",
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 96f4849..2987d72 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
@@ -40,7 +40,10 @@
  * elements must have the same type. An empty depset has type {@code SkylarkType.TOP}, and may be
  * combined with any other depset.
  */
-// TODO(adonovan): move to lib.packages, as this is a Bazelism.
+// TODO(adonovan): move to lib.packages, as this is a Bazelism. Requires:
+// - moving the function to StarlarkLibrary.COMMON.
+// - making SkylarkType.getGenericArgType extensible somehow
+// - relaxing StarlarkThread.checkStateEquals (or defining Depset.equals)
 @SkylarkModule(
     name = "depset",
     category = SkylarkModuleCategory.BUILTIN,
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 178fa02..2635576 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
@@ -252,8 +252,6 @@
     } else if (StarlarkCallable.class.isAssignableFrom(c)) {
       // TODO(adonovan): each StarlarkCallable should report its own type string.
       return "function";
-    } else if (c.equals(SelectorValue.class)) {
-      return "select";
     } else {
       if (c.getSimpleName().isEmpty()) {
         return c.getName();
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 16a9ebc..82ec505 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
@@ -1090,45 +1090,6 @@
     return o instanceof Sequence && ((Sequence) o).isEmpty();
   }
 
-  /**
-   * Returns a function-value implementing "select" (i.e. configurable attributes) in the specified
-   * package context.
-   */
-  @SkylarkCallable(
-      name = "select",
-      doc =
-          "<code>select()</code> is the helper function that makes a rule attribute "
-              + "<a href=\"$BE_ROOT/common-definitions.html#configurable-attributes\">"
-              + "configurable</a>. See "
-              + "<a href=\"$BE_ROOT/functions.html#select\">build encyclopedia</a> for details.",
-      parameters = {
-        @Param(
-            name = "x",
-            type = Dict.class,
-            doc = "The parameter to convert.",
-            // TODO(cparsons): This parameter should be positional-only.
-            legacyNamed = true),
-        @Param(
-            name = "no_match_error",
-            type = String.class,
-            defaultValue = "''",
-            doc = "Optional custom error to report if no condition matches.",
-            named = true)
-      })
-  public Object select(Dict<?, ?> dict, String noMatchError) throws EvalException {
-    if (dict.isEmpty()) {
-      throw Starlark.errorf(
-          "select({}) with an empty dictionary can never resolve because it includes no conditions"
-              + " to match");
-    }
-    for (Object key : dict.keySet()) {
-      if (!(key instanceof String)) {
-        throw Starlark.errorf("Invalid key: %s. select keys must be label references", key);
-      }
-    }
-    return SelectorList.of(new SelectorValue(dict, noMatchError));
-  }
-
   @SkylarkCallable(
       name = "zip",
       doc =
diff --git a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
index 02ed1e0..b834d8f 100644
--- a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
+++ b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
@@ -56,6 +56,7 @@
 import com.google.devtools.build.lib.skylarkbuildapi.stubs.SkylarkAspectStub;
 import com.google.devtools.build.lib.skylarkbuildapi.test.TestingBootstrap;
 import com.google.devtools.build.lib.syntax.BaseFunction;
+import com.google.devtools.build.lib.syntax.Dict;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.EvalUtils;
 import com.google.devtools.build.lib.syntax.Expression;
@@ -65,6 +66,7 @@
 import com.google.devtools.build.lib.syntax.Mutability;
 import com.google.devtools.build.lib.syntax.ParserInput;
 import com.google.devtools.build.lib.syntax.Starlark;
+import com.google.devtools.build.lib.syntax.StarlarkCallable;
 import com.google.devtools.build.lib.syntax.StarlarkFile;
 import com.google.devtools.build.lib.syntax.StarlarkFunction;
 import com.google.devtools.build.lib.syntax.StarlarkSemantics;
@@ -598,6 +600,28 @@
     ImmutableMap.Builder<String, Object> envBuilder = ImmutableMap.builder();
 
     envBuilder.putAll(Starlark.UNIVERSE);
+
+    // Declare a fake implementation of select that just returns the first
+    // value in the dict. (This program is forbidden from depending on the real
+    // implementation of 'select' in lib.packages, and so the hacks multiply.)
+    envBuilder.put(
+        "select",
+        new StarlarkCallable() {
+          @Override
+          public Object fastcall(StarlarkThread thread, Object[] positional, Object[] named)
+              throws EvalException {
+            for (Map.Entry<?, ?> e : ((Dict<?, ?>) positional[0]).entrySet()) {
+              return e.getValue();
+            }
+            throw Starlark.errorf("select: empty dict");
+          }
+
+          @Override
+          public String getName() {
+            return "select";
+          }
+        });
+
     topLevelBootstrap.addBindingsToBuilder(envBuilder);
     androidBootstrap.addBindingsToBuilder(envBuilder);
     appleBootstrap.addBindingsToBuilder(envBuilder);
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java
index e1defc9..8925cca 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java
@@ -401,8 +401,7 @@
         "    name = 'int_key',",
         "    srcs = select({123: ['a.java']})",
         ")");
-    assertTargetError(
-        "//java/foo:int_key", "Invalid key: 123. select keys must be label references");
+    assertTargetError("//java/foo:int_key", "select: got int for dict key, want a label string");
   }
 
   @Test
@@ -414,8 +413,7 @@
         "    name = 'bool_key',",
         "    srcs = select({True: ['a.java']})",
         ")");
-    assertTargetError(
-        "//java/foo:bool_key", "Invalid key: true. select keys must be label references");
+    assertTargetError("//java/foo:bool_key", "select: got bool for dict key, want a label string");
   }
 
   @Test
@@ -428,7 +426,7 @@
         "    srcs = select({None: ['a.java']})",
         ")");
     assertTargetError(
-        "//java/foo:none_key", "Invalid key: None. select keys must be label references");
+        "//java/foo:none_key", "select: got NoneType for dict key, want a label string");
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java b/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java
index 9db91b9..f424e76 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/BuildTypeTest.java
@@ -28,8 +28,6 @@
 import com.google.devtools.build.lib.packages.Type.ConversionException;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.EvalUtils;
-import com.google.devtools.build.lib.syntax.SelectorList;
-import com.google.devtools.build.lib.syntax.SelectorValue;
 import com.google.devtools.build.lib.syntax.Starlark;
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/src/test/java/com/google/devtools/build/lib/packages/SelectTest.java b/src/test/java/com/google/devtools/build/lib/packages/SelectTest.java
new file mode 100644
index 0000000..2cbdff7
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/packages/SelectTest.java
@@ -0,0 +1,76 @@
+// Copyright 2020 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.packages;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
+
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.Module;
+import com.google.devtools.build.lib.syntax.Mutability;
+import com.google.devtools.build.lib.syntax.ParserInput;
+import com.google.devtools.build.lib.syntax.StarlarkThread;
+import com.google.devtools.build.lib.syntax.SyntaxError;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests of @{code select} function and data type. */
+@RunWith(JUnit4.class)
+public class SelectTest {
+
+  private static Object eval(String expr) throws SyntaxError, EvalException, InterruptedException {
+    ParserInput input = ParserInput.fromLines(expr);
+    StarlarkThread thread =
+        StarlarkThread.builder(Mutability.create("test"))
+            .setGlobals(Module.createForBuiltins(StarlarkLibrary.COMMON)) // select et al
+            .useDefaultSemantics()
+            .build();
+    return EvalUtils.eval(input, thread);
+  }
+
+  private static void assertFails(String expr, String wantError) {
+    EvalException ex = assertThrows(EvalException.class, () -> eval(expr));
+    assertThat(ex).hasMessageThat().contains(wantError);
+  }
+
+  @Test
+  public void testSelect() throws Exception {
+    SelectorList result = (SelectorList) eval("select({'a': 1})");
+    assertThat(((SelectorValue) Iterables.getOnlyElement(result.getElements())).getDictionary())
+        .containsExactly("a", 1);
+  }
+
+  @Test
+  public void testPlus() throws Exception {
+    SelectorList x = (SelectorList) eval("select({'foo': ['FOO'], 'bar': ['BAR']}) + []");
+    List<Object> elements = x.getElements();
+    assertThat(elements).hasSize(2);
+    assertThat(elements.get(0)).isInstanceOf(SelectorValue.class);
+    assertThat((Iterable<?>) elements.get(1)).isEmpty();
+  }
+
+  @Test
+  public void testPlusIncompatibleType() throws Exception {
+    assertFails(
+        "select({'foo': ['FOO'], 'bar': ['BAR']}) + 1",
+        "'+' operator applied to incompatible types (select of list, int)");
+    assertFails(
+        "select({'foo': ['FOO']}) + select({'bar': 2})",
+        "'+' operator applied to incompatible types (select of list, select of int)");
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
index c930845..da7e30c 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
@@ -21,7 +21,6 @@
 import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
 import com.google.devtools.build.lib.testutil.TestMode;
 import java.util.Collections;
-import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -606,33 +605,6 @@
         .testExpression("-4 * (1, 2)", Tuple.empty());
   }
 
-  @SuppressWarnings("unchecked")
-  @Test
-  public void testSelectorListConcatenation() throws Exception {
-    // TODO(fwe): cannot be handled by current testing suite
-    SelectorList x = (SelectorList) eval("select({'foo': ['FOO'], 'bar': ['BAR']}) + []");
-    List<Object> elements = x.getElements();
-    assertThat(elements).hasSize(2);
-    assertThat(elements.get(0)).isInstanceOf(SelectorValue.class);
-    assertThat((Iterable<Object>) elements.get(1)).isEmpty();
-  }
-
-  @Test
-  public void testAddSelectIncompatibleType() throws Exception {
-    newTest()
-        .testIfErrorContains(
-            "'+' operator applied to incompatible types (select of list, int)",
-            "select({'foo': ['FOO'], 'bar': ['BAR']}) + 1");
-  }
-
-  @Test
-  public void testAddSelectIncompatibleType2() throws Exception {
-    newTest()
-        .testIfErrorContains(
-            "'+' operator applied to incompatible types (select of list, select of int)",
-            "select({'foo': ['FOO']}) + select({'bar': 2})");
-  }
-
   @Test
   public void testListComprehensionFailsOnNonSequence() throws Exception {
     newTest().testIfErrorContains("type 'int' is not iterable", "[x + 1 for x in 123]");
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
index 39b226e..ec14d4c 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
@@ -14,11 +14,8 @@
 
 package com.google.devtools.build.lib.syntax;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
@@ -625,16 +622,6 @@
         .testExpression("type(str)", "function");
   }
 
-  // TODO(bazel-team): Move select and this test into lib/packages.
-  @Test
-  public void testSelectFunction() throws Exception {
-    enableSkylarkMode();
-    exec("a = select({'a': 1})");
-    SelectorList result = (SelectorList) lookup("a");
-    assertThat(((SelectorValue) Iterables.getOnlyElement(result.getElements())).getDictionary())
-        .containsExactly("a", 1);
-  }
-
   @Test
   public void testZipFunction() throws Exception {
     new BothModesTest()
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java
index 7361fbf..d8806c5 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkThreadTest.java
@@ -125,7 +125,6 @@
                 "range",
                 "repr",
                 "reversed",
-                "select",
                 "sorted",
                 "str",
                 "tuple",