Implement default provider

Default providers can now be used not only to return standard providers values
from a rule implementation function, but also to access these values provided
by other rules.
PiperOrigin-RevId: 152797193
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java
index d32b279..f5313b8 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java
@@ -16,7 +16,6 @@
 
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -27,10 +26,10 @@
 import com.google.devtools.build.lib.packages.PackageSpecification;
 import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
 import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.rules.SkylarkRuleContext;
 import com.google.devtools.build.lib.syntax.ClassObject;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.EvalUtils;
-import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
 import javax.annotation.Nullable;
 
 /**
@@ -108,19 +107,17 @@
 
   @Override
   public Object getValue(String name) {
+    // Standard fields should be proxied to their default provider object
+    DefaultProvider defaultProvider =
+        (DefaultProvider) get(SkylarkRuleContext.getDefaultProvider().getKey());
     switch (name) {
+      case FILES_FIELD:
+      case DEFAULT_RUNFILES_FIELD:
+      case DATA_RUNFILES_FIELD:
+      case FilesToRunProvider.SKYLARK_NAME:
+        return defaultProvider.getValue(name);
       case LABEL_FIELD:
         return getLabel();
-      case FILES_FIELD:
-        // A shortcut for files to build in Skylark. FileConfiguredTarget and RuleConfiguredTarget
-        // always has FileProvider and Error- and PackageGroupConfiguredTarget-s shouldn't be
-        // accessible in Skylark.
-        return SkylarkNestedSet.of(
-            Artifact.class, getProvider(FileProvider.class).getFilesToBuild());
-      case DEFAULT_RUNFILES_FIELD:
-        return RunfilesProvider.DEFAULT_RUNFILES.apply(this);
-      case DATA_RUNFILES_FIELD:
-        return RunfilesProvider.DATA_RUNFILES.apply(this);
       default:
         return get(name);
     }
@@ -173,6 +170,10 @@
   @Override
   public ImmutableCollection<String> getKeys() {
     return ImmutableList.of(
-        DATA_RUNFILES_FIELD, DEFAULT_RUNFILES_FIELD, LABEL_FIELD, FILES_FIELD);
+        DATA_RUNFILES_FIELD,
+        DEFAULT_RUNFILES_FIELD,
+        LABEL_FIELD,
+        FILES_FIELD,
+        FilesToRunProvider.SKYLARK_NAME);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DefaultProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/DefaultProvider.java
new file mode 100644
index 0000000..c0c2a31
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/DefaultProvider.java
@@ -0,0 +1,58 @@
+// Copyright 2017 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.analysis;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.ClassObjectConstructor;
+import com.google.devtools.build.lib.packages.SkylarkClassObject;
+import com.google.devtools.build.lib.rules.SkylarkRuleContext;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import java.util.Map;
+
+/** DefaultProvider is provided by all targets implicitly and contains all standard fields. */
+@Immutable
+public final class DefaultProvider extends SkylarkClassObject {
+
+  // Accessors for Skylark
+  private static final String DATA_RUNFILES_FIELD = "data_runfiles";
+  private static final String DEFAULT_RUNFILES_FIELD = "default_runfiles";
+  private static final String FILES_FIELD = "files";
+
+  private DefaultProvider(ClassObjectConstructor constructor, Map<String, Object> values) {
+    super(constructor, values);
+  }
+
+  public static DefaultProvider build(
+      RunfilesProvider runfilesProvider,
+      FileProvider fileProvider,
+      FilesToRunProvider filesToRunProvider) {
+    ImmutableMap.Builder<String, Object> attrBuilder = new ImmutableMap.Builder<>();
+    if (runfilesProvider != null) {
+      attrBuilder.put(DATA_RUNFILES_FIELD, runfilesProvider.getDataRunfiles());
+      attrBuilder.put(DEFAULT_RUNFILES_FIELD, runfilesProvider.getDefaultRunfiles());
+    } else {
+      attrBuilder.put(DATA_RUNFILES_FIELD, Runfiles.EMPTY);
+      attrBuilder.put(DEFAULT_RUNFILES_FIELD, Runfiles.EMPTY);
+    }
+
+    attrBuilder.put(
+        FILES_FIELD, SkylarkNestedSet.of(Artifact.class, fileProvider.getFilesToBuild()));
+    attrBuilder.put(FilesToRunProvider.SKYLARK_NAME, filesToRunProvider);
+
+    ClassObjectConstructor constructor = SkylarkRuleContext.getDefaultProvider();
+    return new DefaultProvider(constructor, attrBuilder.build());
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java
index 0bc9b53..0fe798b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.analysis;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
@@ -21,6 +22,7 @@
 import com.google.devtools.build.lib.packages.ClassObjectConstructor;
 import com.google.devtools.build.lib.packages.FileTarget;
 import com.google.devtools.build.lib.packages.SkylarkClassObject;
+import com.google.devtools.build.lib.rules.SkylarkRuleContext;
 import com.google.devtools.build.lib.rules.fileset.FilesetProvider;
 import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
 import com.google.devtools.build.lib.util.FileType;
@@ -40,12 +42,22 @@
     super(targetContext);
     NestedSet<Artifact> filesToBuild = NestedSetBuilder.create(Order.STABLE_ORDER, artifact);
     this.artifact = artifact;
+    FileProvider fileProvider = new FileProvider(filesToBuild);
+    FilesToRunProvider filesToRunProvider =
+        FilesToRunProvider.fromSingleExecutableArtifact(artifact);
+    SkylarkClassObject defaultProvider =
+        DefaultProvider.build(null, fileProvider, filesToRunProvider);
+    SkylarkProviders skylarkProviders =
+        new SkylarkProviders(
+            ImmutableMap.<String, Object>of(),
+            ImmutableMap.of(SkylarkRuleContext.getDefaultProvider().getKey(), defaultProvider));
     TransitiveInfoProviderMap.Builder builder =
         TransitiveInfoProviderMap.builder()
             .put(VisibilityProvider.class, this)
             .put(LicensesProvider.class, this)
-            .add(new FileProvider(filesToBuild))
-            .add(FilesToRunProvider.fromSingleExecutableArtifact(artifact));
+            .put(SkylarkProviders.class, skylarkProviders)
+            .add(fileProvider)
+            .add(filesToRunProvider);
     if (this instanceof FilesetProvider) {
       builder.put(FilesetProvider.class, this);
     }
@@ -86,6 +98,6 @@
   @Nullable
   @Override
   public SkylarkClassObject get(ClassObjectConstructor.Key providerKey) {
-    return null;
+    return getProvider(SkylarkProviders.class).getDeclaredProvider(providerKey);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java
index 51954c13..7ba2eff 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java
@@ -53,7 +53,7 @@
 @Immutable
 public final class OutputGroupProvider implements
     TransitiveInfoProvider, SkylarkIndexable, Iterable<String> {
-  public static String SKYLARK_NAME = "output_groups";
+  public static final String SKYLARK_NAME = "output_groups";
 
   /**
    * Prefix for output groups that are not reported to the user on the terminal output of Blaze when
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
index 9bab046..077e2ec 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
@@ -92,7 +92,6 @@
         getFilesToRun(runfilesSupport, filesToBuild), runfilesSupport, executable);
     addProvider(new FileProvider(filesToBuild));
     addProvider(filesToRunProvider);
-    addSkylarkTransitiveInfo(FilesToRunProvider.SKYLARK_NAME, filesToRunProvider);
 
     if (runfilesSupport != null) {
       // If a binary is built, build its runfiles, too
@@ -136,6 +135,14 @@
       addSkylarkTransitiveInfo(OutputGroupProvider.SKYLARK_NAME, outputGroupProvider);
     }
 
+    // Populate default provider fields and build it
+    DefaultProvider defaultProvider =
+        DefaultProvider.build(
+            providersBuilder.getProvider(RunfilesProvider.class),
+            providersBuilder.getProvider(FileProvider.class),
+            filesToRunProvider);
+    skylarkDeclaredProviders.put(defaultProvider.getConstructor().getKey(), defaultProvider);
+
     TransitiveInfoProviderMap providers = providersBuilder.build();
     addRegisteredProvidersToSkylarkProviders(providers);