Add a isLoadingPhase flag to Environment

Have loadingPhase-only methods check that flag.
It's no use removing the initial bindings to these methods
when they may have been copied anyway.

--
MOS_MIGRATED_REVID=101624770
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 40253e5..3bea243 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -390,6 +390,7 @@
     for (Map.Entry<String, SkylarkType> entry : skylarkAccessibleJavaClasses.entrySet()) {
       env.update(entry.getKey(), entry.getValue().getType());
     }
+    env.setLoadingPhase();
     return env;
   }
 
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 ed2832b..4fdd77e 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
@@ -939,6 +939,7 @@
       public Environment.NoneType invoke(Map<String, Object> kwargs,
           FuncallExpression ast, Environment env)
           throws EvalException {
+        env.checkLoadingPhase(ruleClass, ast.getLocation());
         try {
           addRule(ruleFactory, ruleClass, getContext(env, ast), kwargs, ast);
         } catch (RuleFactory.InvalidRuleException | Package.NameConflictException e) {
@@ -1233,6 +1234,7 @@
     // Important: Environment should be unreachable by the end of this method!
     StoredEventHandler eventHandler = new StoredEventHandler();
     Environment pkgEnv = new Environment(globalEnv, eventHandler);
+    pkgEnv.setLoadingPhase();
 
     Package.LegacyBuilder pkgBuilder = new Package.LegacyBuilder(packageId);
 
@@ -1302,6 +1304,7 @@
     }
     // Important: Environment should be unreachable by the end of this method!
     Environment pkgEnv = new Environment();
+    pkgEnv.setLoadingPhase();
 
     Package.LegacyBuilder pkgBuilder = new Package.LegacyBuilder(packageId);
 
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 7195d10..c2186b9 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
@@ -62,6 +62,7 @@
           SkylarkList include, SkylarkList exclude, SkylarkList excludes,
           Integer excludeDirectories, FuncallExpression ast, Environment env)
           throws EvalException, ConversionException, InterruptedException {
+        env.checkLoadingPhase("native.glob", ast.getLocation());
         // TODO(bazel-team): Remove 'excludes' argument in July 2015.
         if (exclude.size() == 0) {
           exclude = excludes;
@@ -89,6 +90,7 @@
   private static final BuiltinFunction packageGroup = new BuiltinFunction("package_group") {
       public Environment.NoneType invoke(String name, SkylarkList packages, SkylarkList includes,
                 FuncallExpression ast, Environment env) throws EvalException, ConversionException {
+        env.checkLoadingPhase("native.package_group", ast.getLocation());
         return PackageFactory.callPackageFunction(name, packages, includes, ast, env);
       }
     };
@@ -114,6 +116,7 @@
       public Environment.NoneType invoke(SkylarkList srcs, Object visibility, Object licenses,
           FuncallExpression ast, Environment env)
           throws EvalException, ConversionException {
+        env.checkLoadingPhase("native.exports_file", ast.getLocation());
         return PackageFactory.callExportsFiles(srcs, visibility, licenses, ast, env);
       }
     };
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 d72d8aa..4a312f7 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
@@ -142,6 +142,7 @@
       Builder builder, RuleClassProvider ruleClassProvider, String installDir) {
     Environment workspaceEnv = new Environment();
     MethodLibrary.setupMethodEnvironment(workspaceEnv);
+    workspaceEnv.setLoadingPhase();
 
     RuleFactory ruleFactory = new RuleFactory(ruleClassProvider);
     for (String ruleClass : ruleFactory.getRuleClassNames()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
index 9c3fedf..35dfa4d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
@@ -226,6 +226,7 @@
             Environment env)
             throws EvalException {
           // TODO(bazel-team): Replace literal strings with constants.
+          env.checkLoadingPhase("attr.int", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG, defaultInt, MANDATORY_ARG, mandatory, VALUES_ARG, values),
@@ -269,6 +270,7 @@
             FuncallExpression ast,
             Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.string", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG, defaultString, MANDATORY_ARG, mandatory, VALUES_ARG, values),
@@ -356,6 +358,7 @@
             FuncallExpression ast,
             Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.label", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG,
@@ -410,6 +413,7 @@
             FuncallExpression ast,
             Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.string_list", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG, defaultList, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
@@ -449,6 +453,7 @@
             FuncallExpression ast,
             Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.int_list", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG, defaultList, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
@@ -533,6 +538,7 @@
             FuncallExpression ast,
             Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.label_list", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG,
@@ -575,6 +581,7 @@
         public Attribute.Builder<?> invoke(
             Boolean defaultO, Boolean mandatory, FuncallExpression ast, Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.bool", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
               Type.BOOLEAN,
@@ -610,6 +617,7 @@
         public Attribute.Builder<?> invoke(
             Object defaultO, Boolean mandatory, FuncallExpression ast, Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.output", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
               Type.OUTPUT,
@@ -650,6 +658,7 @@
             FuncallExpression ast,
             Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.output_list", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG, defaultList, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
@@ -685,6 +694,7 @@
             FuncallExpression ast,
             Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.string_dict", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(
                   DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
@@ -714,6 +724,7 @@
         public Attribute.Builder<?> invoke(
             Object defaultO, Boolean mandatory, FuncallExpression ast, Environment env)
             throws EvalException {
+          env.checkLoadingPhase("attr.license", ast.getLocation());
           return createAttribute(
               EvalUtils.optionMap(DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
               Type.LICENSE,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index b1c48d4..da14fc6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -27,7 +27,6 @@
 import static com.google.devtools.build.lib.syntax.SkylarkType.castMap;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
@@ -234,7 +233,7 @@
           SkylarkList fragments, FuncallExpression ast, Environment funcallEnv)
           throws EvalException, ConversionException {
 
-        Preconditions.checkState(funcallEnv instanceof SkylarkEnvironment);
+        funcallEnv.checkLoadingPhase("rule", ast.getLocation());
         RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL;
 
         // We'll set the name later, pass the empty string for now.
@@ -310,6 +309,7 @@
     // to be a PackageContext
     public Object call(Object[] args, FuncallExpression ast, Environment env)
         throws EvalException, InterruptedException, ConversionException {
+      env.checkLoadingPhase(getName(), ast.getLocation());
       try {
         if (ruleClassName == null || skylarkFile == null) {
           throw new EvalException(ast.getLocation(),
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
index 3acbec1..b6acb05 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
@@ -20,6 +20,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.vfs.PathFragment;
 
 import java.util.ArrayList;
@@ -100,6 +101,38 @@
    */
   protected Set<String> propagatingVariables = new HashSet<>();
 
+  // Only used in the global environment.
+  // TODO(bazel-team): make this a final field part of constructor.
+  private boolean isLoadingPhase = false;
+
+  /**
+   * Is this Environment being evaluated during the loading phase?
+   * This is fixed during environment setup, and enables various functions
+   * that are not available during the analysis phase.
+   * @return true if this environment corresponds to code during the loading phase.
+   */
+  boolean isLoadingPhase() {
+    return isLoadingPhase;
+  }
+
+  /**
+   * Enable loading phase only functions in this Environment.
+   * This should only be done during setup before code is evaluated.
+   */
+  public void setLoadingPhase() {
+    isLoadingPhase = true;
+  }
+
+  /**
+   * Checks that the current Evaluation context is in loading phase.
+   * @param symbol name of the function being only authorized thus.
+   */
+  public void checkLoadingPhase(String symbol, Location loc) throws EvalException {
+    if (!isLoadingPhase()) {
+      throw new EvalException(loc, symbol + "() can only be called during the loading phase");
+    }
+  }
+
   /**
    * Is this a global environment?
    * @return true if this is a global (top-level) environment
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
index 8e2a5c3..c200b83 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
@@ -69,6 +69,10 @@
         // Always use the caller Environment's EventHandler. We cannot assume that the
         // definition Environment's EventHandler is still working properly.
         new SkylarkEnvironment(definitionEnv, stackTrace, callerEnv.eventHandler);
+    if (callerEnv.isLoadingPhase()) {
+      childEnv.setLoadingPhase();
+    }
+
     try {
       for (String varname : callerEnv.propagatingVariables) {
         childEnv.updateAndPropagate(varname, callerEnv.lookup(varname));