Split Info into SkylarkInfo and NativeInfo.

Prerequisite to implementing shape-declaration and shape-sharing
for declared providers, and cleaning up NativeInfo interface.

RELNOTES: None.
PiperOrigin-RevId: 166057070
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ActionsProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ActionsProvider.java
index 90441ee..ac7ade3 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ActionsProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ActionsProvider.java
@@ -16,8 +16,10 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.packages.Info;
 import com.google.devtools.build.lib.packages.NativeProvider;
+import com.google.devtools.build.lib.packages.SkylarkInfo;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -44,6 +46,6 @@
       }
     }
     ImmutableMap<String, Object> fields = ImmutableMap.<String, Object>of("by_file", map);
-    return new Info(SKYLARK_CONSTRUCTOR, fields);
+    return new SkylarkInfo(SKYLARK_CONSTRUCTOR, fields, Location.BUILTIN);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DefaultInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/DefaultInfo.java
index 7becc71..a9b5461 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/DefaultInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/DefaultInfo.java
@@ -19,16 +19,15 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
-import com.google.devtools.build.lib.packages.Provider;
 import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 
 /** DefaultInfo is provided by all targets implicitly and contains all standard fields. */
 @Immutable
-public final class DefaultInfo extends Info {
+public final class DefaultInfo extends NativeInfo {
 
   // Accessors for Skylark
   private static final String DATA_RUNFILES_FIELD = "data_runfiles";
@@ -47,23 +46,24 @@
   private final AtomicReference<SkylarkNestedSet> files = new AtomicReference<>();
 
   public static final String SKYLARK_NAME = "DefaultInfo";
-  public static final Provider PROVIDER =
-      new NativeProvider<Info>(Info.class, SKYLARK_NAME) {
+
+  // todo(dslomov,vladmos): make this provider return DefaultInfo.
+  public static final NativeProvider<NativeInfo> PROVIDER =
+      new NativeProvider<NativeInfo>(NativeInfo.class, SKYLARK_NAME) {
         @Override
-        protected Info createInstanceFromSkylark(Object[] args, Location loc) {
+        protected NativeInfo createInstanceFromSkylark(Object[] args, Location loc) {
           @SuppressWarnings("unchecked")
           Map<String, Object> kwargs = (Map<String, Object>) args[0];
-          return new Info(this, kwargs, loc);
+          return new NativeInfo(this, kwargs, loc);
         }
       };
 
   private DefaultInfo(
-      Provider constructor,
       RunfilesProvider runfilesProvider,
       FileProvider fileProvider,
       FilesToRunProvider filesToRunProvider) {
     // Fields map is not used here to prevent memory regression
-    super(constructor, ImmutableMap.<String, Object>of());
+    super(PROVIDER, ImmutableMap.<String, Object>of());
     this.runfilesProvider = runfilesProvider;
     this.fileProvider = fileProvider;
     this.filesToRunProvider = filesToRunProvider;
@@ -73,8 +73,7 @@
       RunfilesProvider runfilesProvider,
       FileProvider fileProvider,
       FilesToRunProvider filesToRunProvider) {
-    return new DefaultInfo(
-        PROVIDER, runfilesProvider, fileProvider, filesToRunProvider);
+    return new DefaultInfo(runfilesProvider, fileProvider, filesToRunProvider);
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/MakeVariableInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/MakeVariableInfo.java
index d33af68..d4bb747 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/MakeVariableInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/MakeVariableInfo.java
@@ -16,7 +16,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -24,7 +24,7 @@
 /** Provides access to make variables from the current fragments. */
 @SkylarkModule(name = "MakeVariables", doc = "Make variables exposed by the current target.")
 @Immutable
-public final class MakeVariableInfo extends Info {
+public final class MakeVariableInfo extends NativeInfo {
   public static final String SKYLARK_NAME = "MakeVariableInfo";
 
   public static final NativeProvider<MakeVariableInfo> PROVIDER =
@@ -33,7 +33,7 @@
   private final ImmutableMap<String, String> makeVariables;
 
   public MakeVariableInfo(ImmutableMap<String, String> makeVariables) {
-    super(PROVIDER, ImmutableMap.<String, Object>of());
+    super(PROVIDER);
     this.makeVariables = makeVariables;
   }
 
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 e367af6..3ee2c7e 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
@@ -29,7 +29,7 @@
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.EvalUtils;
@@ -57,7 +57,8 @@
  * not mentioned on the output.
  */
 @Immutable
-public final class OutputGroupProvider extends Info implements SkylarkIndexable, Iterable<String> {
+public final class OutputGroupProvider extends NativeInfo
+    implements SkylarkIndexable, Iterable<String> {
   public static final String SKYLARK_NAME = "output_groups";
 
   public static NativeProvider<OutputGroupProvider> SKYLARK_CONSTRUCTOR = new Constructor();
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintSettingInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintSettingInfo.java
index 6ba8b5a..9554692 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintSettingInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintSettingInfo.java
@@ -19,7 +19,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -35,7 +35,7 @@
   category = SkylarkModuleCategory.PROVIDER
 )
 @Immutable
-public class ConstraintSettingInfo extends Info {
+public class ConstraintSettingInfo extends NativeInfo {
 
   /** Name used in Skylark for accessing this provider. */
   public static final String SKYLARK_NAME = "ConstraintSettingInfo";
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintValueInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintValueInfo.java
index 53d8ae1..d9b167b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintValueInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/ConstraintValueInfo.java
@@ -19,7 +19,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -35,7 +35,7 @@
   category = SkylarkModuleCategory.PROVIDER
 )
 @Immutable
-public class ConstraintValueInfo extends Info {
+public class ConstraintValueInfo extends NativeInfo {
 
   /** Name used in Skylark for accessing this provider. */
   public static final String SKYLARK_NAME = "ConstraintValueInfo";
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformInfo.java
index 8d8b669..be05d75 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformInfo.java
@@ -22,7 +22,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -44,7 +44,7 @@
   category = SkylarkModuleCategory.PROVIDER
 )
 @Immutable
-public class PlatformInfo extends Info {
+public class PlatformInfo extends NativeInfo {
 
   /** Name used in Skylark for accessing this provider. */
   public static final String SKYLARK_NAME = "PlatformInfo";
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java
index bff0be6..c5af6fd 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java
@@ -18,7 +18,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Location;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
@@ -38,7 +38,7 @@
   category = SkylarkModuleCategory.PROVIDER
 )
 @Immutable
-public class ToolchainInfo extends Info {
+public class ToolchainInfo extends NativeInfo {
 
   /** Name used in Skylark for accessing this provider. */
   public static final String SKYLARK_NAME = "ToolchainInfo";
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/ExecutionInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/test/ExecutionInfo.java
index 9dfa3d7..8b60872 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/ExecutionInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/ExecutionInfo.java
@@ -15,7 +15,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import java.util.Map;
 
@@ -24,7 +24,7 @@
  * tests).
  */
 @Immutable
-public final class ExecutionInfo extends Info {
+public final class ExecutionInfo extends NativeInfo {
 
   /** Skylark constructor and identifier for ExecutionInfo. */
   public static final NativeProvider<ExecutionInfo> PROVIDER =
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestEnvironmentInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestEnvironmentInfo.java
index ec16185..013ff33 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestEnvironmentInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/TestEnvironmentInfo.java
@@ -17,13 +17,13 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import java.util.Map;
 
 /** Provider containing any additional environment variables for use in the test action. */
 @Immutable
-public final class TestEnvironmentInfo extends Info {
+public final class TestEnvironmentInfo extends NativeInfo {
 
   /** Skylark constructor and identifier for TestEnvironmentInfo. */
   public static final NativeProvider<TestEnvironmentInfo> PROVIDER =
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Info.java b/src/main/java/com/google/devtools/build/lib/packages/Info.java
index 059c55e..6c004e2 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Info.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Info.java
@@ -15,20 +15,15 @@
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Ordering;
-import com.google.common.collect.Sets;
-import com.google.common.collect.Sets.SetView;
 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 com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.syntax.ClassObject;
-import com.google.devtools.build.lib.syntax.Concatable;
 import com.google.devtools.build.lib.syntax.EvalException;
-import com.google.devtools.build.lib.syntax.EvalUtils;
 import com.google.devtools.build.lib.syntax.Printer;
 import com.google.devtools.build.lib.syntax.SkylarkType;
 import com.google.devtools.build.lib.util.Preconditions;
@@ -48,24 +43,21 @@
           + "See the global <a href=\"globals.html#struct\">struct</a> function "
           + "for more details."
 )
-public class Info implements ClassObject, SkylarkValue, Concatable, Serializable {
+public abstract class Info implements ClassObject, SkylarkValue, Serializable {
   private final Provider provider;
-  private final ImmutableMap<String, Object> values;
   private final Location creationLoc;
   private final String errorMessage;
 
   /** Creates an empty struct with a given location. */
   public Info(Provider provider, Location location) {
     this.provider = provider;
-    this.values = ImmutableMap.of();
     this.creationLoc = location;
     this.errorMessage = provider.getErrorMessageFormatForInstances();
   }
 
   /** Creates a built-in struct (i.e. without creation loc). */
-  public Info(Provider provider, Map<String, Object> values) {
+  public Info(Provider provider) {
     this.provider = provider;
-    this.values = copyValues(values);
     this.creationLoc = null;
     this.errorMessage = provider.getErrorMessageFormatForInstances();
   }
@@ -80,20 +72,12 @@
    */
   Info(Provider provider, Map<String, Object> values, String errorMessage) {
     this.provider = provider;
-    this.values = copyValues(values);
     this.creationLoc = null;
     this.errorMessage = Preconditions.checkNotNull(errorMessage);
   }
 
-  public Info(Provider provider, Map<String, Object> values, Location creationLoc) {
-    this.provider = provider;
-    this.values = copyValues(values);
-    this.creationLoc = Preconditions.checkNotNull(creationLoc);
-    this.errorMessage = provider.getErrorMessageFormatForInstances();
-  }
-
   // Ensure that values are all acceptable to Skylark before to stuff them in a ClassObject
-  private ImmutableMap<String, Object> copyValues(Map<String, Object> values) {
+  protected static ImmutableMap<String, Object> copyValues(Map<String, Object> values) {
     ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
     for (Map.Entry<String, Object> e : values.entrySet()) {
       builder.put(
@@ -102,18 +86,11 @@
     return builder.build();
   }
 
-  @Override
-  public Object getValue(String name) {
-    return values.get(name);
-  }
-
-  public boolean hasKey(String name) {
-    return values.containsKey(name);
-  }
+  public abstract boolean hasKey(String name);
 
   /** Returns a value and try to cast it into specified type */
   public <TYPE> TYPE getValue(String key, Class<TYPE> type) throws EvalException {
-    Object obj = values.get(key);
+    Object obj = getValue(key);
     if (obj == null) {
       return null;
     }
@@ -121,20 +98,10 @@
     return type.cast(obj);
   }
 
-  @Override
-  public ImmutableCollection<String> getKeys() {
-    return values.keySet();
-  }
-
   public Location getCreationLoc() {
     return Preconditions.checkNotNull(creationLoc, "This struct was not created in a Skylark code");
   }
 
-  @Override
-  public Concatter getConcatter() {
-    return StructConcatter.INSTANCE;
-  }
-
   public Provider getProvider() {
     return provider;
   }
@@ -144,58 +111,14 @@
     return creationLoc;
   }
 
-  private static class StructConcatter implements Concatter {
-    private static final StructConcatter INSTANCE = new StructConcatter();
-
-    private StructConcatter() {}
-
-    @Override
-    public Info concat(Concatable left, Concatable right, Location loc) throws EvalException {
-      Info lval = (Info) left;
-      Info rval = (Info) right;
-      if (!lval.provider.equals(rval.provider)) {
-        throw new EvalException(
-            loc,
-            String.format(
-                "Cannot concat %s with %s",
-                lval.provider.getPrintableName(), rval.provider.getPrintableName()));
-      }
-      SetView<String> commonFields = Sets.intersection(lval.values.keySet(), rval.values.keySet());
-      if (!commonFields.isEmpty()) {
-        throw new EvalException(
-            loc,
-            "Cannot concat structs with common field(s): " + Joiner.on(",").join(commonFields));
-      }
-      return new Info(
-          lval.provider,
-          ImmutableMap.<String, Object>builder().putAll(lval.values).putAll(rval.values).build(),
-          loc);
-    }
-  }
-
   @Override
   public String errorMessage(String name) {
     String suffix =
-        "Available attributes: "
-            + Joiner.on(", ").join(Ordering.natural().sortedCopy(values.keySet()));
+        "Available attributes: " + Joiner.on(", ").join(Ordering.natural().sortedCopy(getKeys()));
     return String.format(errorMessage, name) + "\n" + suffix;
   }
 
   @Override
-  public boolean isImmutable() {
-    // If the provider is not yet exported the hash code of the object is subject to change
-    if (!provider.isExported()) {
-      return false;
-    }
-    for (Object item : values.values()) {
-      if (!EvalUtils.isImmutable(item)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  @Override
   public boolean equals(Object otherObject) {
     if (!(otherObject instanceof Info)) {
       return false;
@@ -241,14 +164,14 @@
     boolean first = true;
     printer.append("struct(");
     // Sort by key to ensure deterministic output.
-    for (String key : Ordering.natural().sortedCopy(values.keySet())) {
+    for (String key : Ordering.natural().sortedCopy(getKeys())) {
       if (!first) {
         printer.append(", ");
       }
       first = false;
       printer.append(key);
       printer.append(" = ");
-      printer.repr(values.get(key));
+      printer.repr(getValue(key));
     }
     printer.append(")");
   }
@@ -259,14 +182,14 @@
     printer.append(provider.getPrintableName());
     printer.append("(");
     // Sort by key to ensure deterministic output.
-    for (String key : Ordering.natural().sortedCopy(values.keySet())) {
+    for (String key : Ordering.natural().sortedCopy(getKeys())) {
       if (!first) {
         printer.append(", ");
       }
       first = false;
       printer.append(key);
       printer.append(" = ");
-      printer.repr(values.get(key));
+      printer.repr(getValue(key));
     }
     printer.append(")");
   }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/NativeInfo.java b/src/main/java/com/google/devtools/build/lib/packages/NativeInfo.java
new file mode 100644
index 0000000..d52fa87
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/packages/NativeInfo.java
@@ -0,0 +1,54 @@
+// 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.packages;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.events.Location;
+import java.util.Map;
+
+/** Base class for native implementations of {@link Info}. */
+// todo(vladmos,dslomov): make abstract once DefaultInfo stops instantiating it.
+public class NativeInfo extends Info {
+  protected final ImmutableMap<String, Object> values;
+
+  @Override
+  public Object getValue(String name) {
+    return values.get(name);
+  }
+
+  @Override
+  public boolean hasKey(String name) {
+    return values.containsKey(name);
+  }
+
+  @Override
+  public ImmutableCollection<String> getKeys() {
+    return values.keySet();
+  }
+
+  public NativeInfo(NativeProvider<?> provider) {
+    super(provider, Location.BUILTIN);
+    this.values = ImmutableMap.of();
+  }
+
+  public NativeInfo(NativeProvider<?> provider, Map<String, Object> values, Location loc) {
+    super(provider, loc);
+    this.values = copyValues(values);
+  }
+
+  public NativeInfo(NativeProvider<?> provider, Map<String, Object> values) {
+    this(provider, values, Location.BUILTIN);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/NativeProvider.java b/src/main/java/com/google/devtools/build/lib/packages/NativeProvider.java
index f400255..39b87cc 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/NativeProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/NativeProvider.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.packages;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.syntax.EvalException;
@@ -78,15 +79,15 @@
     protected Info createInstanceFromSkylark(Object[] args, Location loc) {
       @SuppressWarnings("unchecked")
       Map<String, Object> kwargs = (Map<String, Object>) args[0];
-      return new Info(this, kwargs, loc);
+      return new SkylarkInfo(this, kwargs, loc);
     }
 
     public Info create(Map<String, Object> values, String message) {
-      return new Info(this, values, message);
+      return new SkylarkInfo(this, values, message);
     }
 
     public Info create(Location loc) {
-      return new Info(this, loc);
+      return new SkylarkInfo(this, ImmutableMap.of(), loc);
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkInfo.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkInfo.java
new file mode 100644
index 0000000..755a5df
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkInfo.java
@@ -0,0 +1,105 @@
+// 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.packages;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.NativeProvider.StructConstructor;
+import com.google.devtools.build.lib.syntax.Concatable;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import java.util.Map;
+
+/** Implementation of {@link Info} created from Skylark. */
+public final class SkylarkInfo extends Info implements Concatable {
+  protected final ImmutableMap<String, Object> values;
+
+  public SkylarkInfo(Provider provider, Map<String, Object> kwargs, Location loc) {
+    super(provider, loc);
+    this.values = copyValues(kwargs);
+  }
+
+  public SkylarkInfo(StructConstructor provider, Map<String, Object> values, String message) {
+    super(provider, values, message);
+    this.values = copyValues(values);
+  }
+
+  @Override
+  public Concatter getConcatter() {
+    return StructConcatter.INSTANCE;
+  }
+
+  @Override
+  public Object getValue(String name) {
+    return values.get(name);
+  }
+
+  @Override
+  public boolean hasKey(String name) {
+    return values.containsKey(name);
+  }
+
+  @Override
+  public ImmutableCollection<String> getKeys() {
+    return values.keySet();
+  }
+
+  @Override
+  public boolean isImmutable() {
+    // If the provider is not yet exported the hash code of the object is subject to change
+    if (!getProvider().isExported()) {
+      return false;
+    }
+    for (Object item : values.values()) {
+      if (!EvalUtils.isImmutable(item)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  private static class StructConcatter implements Concatter {
+    private static final StructConcatter INSTANCE = new StructConcatter();
+
+    private StructConcatter() {}
+
+    @Override
+    public SkylarkInfo concat(Concatable left, Concatable right, Location loc)
+        throws EvalException {
+      SkylarkInfo lval = (SkylarkInfo) left;
+      SkylarkInfo rval = (SkylarkInfo) right;
+      if (!lval.getProvider().equals(rval.getProvider())) {
+        throw new EvalException(
+            loc,
+            String.format(
+                "Cannot concat %s with %s",
+                lval.getProvider().getPrintableName(), rval.getProvider().getPrintableName()));
+      }
+      SetView<String> commonFields = Sets.intersection(lval.values.keySet(), rval.values.keySet());
+      if (!commonFields.isEmpty()) {
+        throw new EvalException(
+            loc,
+            "Cannot concat structs with common field(s): " + Joiner.on(",").join(commonFields));
+      }
+      return new SkylarkInfo(
+          lval.getProvider(),
+          ImmutableMap.<String, Object>builder().putAll(lval.values).putAll(rval.values).build(),
+          loc);
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java
index 8489d81..d76c006 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java
@@ -60,7 +60,7 @@
   protected Info createInstanceFromSkylark(Object[] args, Location loc) throws EvalException {
     @SuppressWarnings("unchecked")
     Map<String, Object> kwargs = (Map<String, Object>) args[0];
-    return new Info(this, kwargs, loc);
+    return new SkylarkInfo(this, kwargs, loc);
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureInfoProvider.java
index 27689da..6333adc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureInfoProvider.java
@@ -17,7 +17,7 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 
 /**
@@ -25,7 +25,7 @@
  * android_instrumentation_test}.
  */
 @Immutable
-public class AndroidDeviceScriptFixtureInfoProvider extends Info {
+public class AndroidDeviceScriptFixtureInfoProvider extends NativeInfo {
 
   private static final String SKYLARK_NAME = "DeviceScriptFixtureInfo";
   public static final NativeProvider<AndroidDeviceScriptFixtureInfoProvider> SKYLARK_CONSTRUCTOR =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixtureInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixtureInfoProvider.java
index e37a693..2dd0cfe 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixtureInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixtureInfoProvider.java
@@ -18,7 +18,7 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 
 /**
@@ -26,7 +26,7 @@
  * android_instrumentation_test}.
  */
 @Immutable
-public class AndroidHostServiceFixtureInfoProvider extends Info {
+public class AndroidHostServiceFixtureInfoProvider extends NativeInfo {
 
   private static final String SKYLARK_NAME = "HostServiceFixtureInfo";
   static final NativeProvider<AndroidHostServiceFixtureInfoProvider>
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationInfoProvider.java
index 530096e..70659fc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationInfoProvider.java
@@ -16,7 +16,7 @@
 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.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 
 /**
@@ -24,7 +24,7 @@
  * AndroidInstrumentationTest}.
  */
 @Immutable
-public class AndroidInstrumentationInfoProvider extends Info {
+public class AndroidInstrumentationInfoProvider extends NativeInfo {
 
   private static final String SKYLARK_NAME = "AndroidInstrumentationInfo";
   static final NativeProvider<AndroidInstrumentationInfoProvider> ANDROID_INSTRUMENTATION_INFO =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/ApplePlatform.java b/src/main/java/com/google/devtools/build/lib/rules/apple/ApplePlatform.java
index bccee16..6e9a2b6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/ApplePlatform.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/ApplePlatform.java
@@ -16,9 +16,11 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.packages.Info;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.packages.Provider;
+import com.google.devtools.build.lib.packages.SkylarkInfo;
 import com.google.devtools.build.lib.skyframe.serialization.EnumCodec;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -219,7 +221,7 @@
     for (ApplePlatform type : values()) {
       fields.put(type.skylarkKey, type);
     }
-    return new Info(constructor, fields);
+    return new SkylarkInfo(constructor, fields, Location.BUILTIN);
   }
 
   @Override
@@ -293,7 +295,7 @@
       for (PlatformType type : values()) {
         fields.put(type.skylarkKey, type);
       }
-      return new Info(constructor, fields);
+      return new SkylarkInfo(constructor, fields, Location.BUILTIN);
     }
 
     @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProperties.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProperties.java
index a75fae2..073a9f7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProperties.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProperties.java
@@ -19,14 +19,14 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import java.util.Map;
 import javax.annotation.Nullable;
 
 /** A tuple containing information about a version of xcode and its properties. */
 @Immutable
-public class XcodeVersionProperties extends Info {
+public class XcodeVersionProperties extends NativeInfo {
 
   /** Skylark name for the XcodeVersionProperties provider. */
   public static final String SKYLARK_NAME = "XcodeProperties";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagProvider.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagProvider.java
index 8e5f0d5..588ef28 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagProvider.java
@@ -18,7 +18,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
 import com.google.devtools.build.lib.skylarkinterface.Param;
@@ -31,7 +31,7 @@
   doc = "A provider used to access information about config_feature_flag rules."
 )
 @Immutable
-public class ConfigFeatureFlagProvider extends Info {
+public class ConfigFeatureFlagProvider extends NativeInfo {
 
   /** Name used in Skylark for accessing ConfigFeatureFlagProvider. */
   static final String SKYLARK_NAME = "FeatureFlagInfo";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParamsInfo.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParamsInfo.java
index 5f91a25..e95080e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParamsInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParamsInfo.java
@@ -18,13 +18,13 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.rules.cpp.CcLinkParamsStore.CcLinkParamsStoreImpl;
 
 /** A target that provides C linker parameters. */
 @Immutable
-public final class CcLinkParamsInfo extends Info {
+public final class CcLinkParamsInfo extends NativeInfo {
   public static final NativeProvider<CcLinkParamsInfo> PROVIDER =
       new NativeProvider<CcLinkParamsInfo>(CcLinkParamsInfo.class, "link_params") {};
   public static final Function<TransitiveInfoCollection, CcLinkParamsStore> TO_LINK_PARAMS =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java
index 81da786..46c45c6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java
@@ -24,7 +24,7 @@
 import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
 import java.util.ArrayList;
@@ -34,7 +34,7 @@
 
 /** A Skylark declared provider that encapsulates all providers that are needed by Java rules. */
 @Immutable
-public final class JavaInfo extends Info {
+public final class JavaInfo extends NativeInfo {
 
   public static final NativeProvider<JavaInfo> PROVIDER =
       new NativeProvider<JavaInfo>(JavaInfo.class, "java_common.provider") {};
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java
index 32b830c..87df25f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeInfo.java
@@ -18,7 +18,7 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -27,7 +27,7 @@
 /** Information about the Java runtime used by the <code>java_*</code> rules. */
 @SkylarkModule(name = "JavaRuntimeInfo", doc = "Information about the Java runtime being used.")
 @Immutable
-public class JavaRuntimeInfo extends Info {
+public class JavaRuntimeInfo extends NativeInfo {
   public static final String SKYLARK_NAME = "JavaRuntimeInfo";
 
   public static final NativeProvider<JavaRuntimeInfo> PROVIDER =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDebugOutputsProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDebugOutputsProvider.java
index 0e55524..cf476ba 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDebugOutputsProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDebugOutputsProvider.java
@@ -17,7 +17,7 @@
 import com.google.common.collect.Maps;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import java.util.HashMap;
 import java.util.Map.Entry;
@@ -37,7 +37,7 @@
  * <p>Example: { "arm64": { "bitcode_symbols": Artifact, "dsym_binary": Artifact } }
  */
 @Immutable
-public final class AppleDebugOutputsProvider extends Info {
+public final class AppleDebugOutputsProvider extends NativeInfo {
 
   /** Expected types of debug outputs. */
   enum OutputType {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDylibBinaryProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDylibBinaryProvider.java
index 248a13c..2328a45 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDylibBinaryProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDylibBinaryProvider.java
@@ -16,7 +16,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 
 /**
@@ -30,7 +30,7 @@
  *       avoid relinking symbols included in the dylib
  * </ul>
  */
-public final class AppleDylibBinaryProvider extends Info {
+public final class AppleDylibBinaryProvider extends NativeInfo {
 
   /** Skylark name for the AppleDylibBinaryProvider. */
   public static final String SKYLARK_NAME = "AppleDylibBinary";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDynamicFrameworkProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDynamicFrameworkProvider.java
index 994afec..21ba059 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDynamicFrameworkProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleDynamicFrameworkProvider.java
@@ -17,7 +17,7 @@
 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.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import javax.annotation.Nullable;
@@ -36,7 +36,7 @@
  *       executable may avoid relinking symbols included in the loadable binary
  * </ul>
  */
-public final class AppleDynamicFrameworkProvider extends Info {
+public final class AppleDynamicFrameworkProvider extends NativeInfo {
 
   /** Skylark name for the AppleDynamicFrameworkProvider. */
   public static final String SKYLARK_NAME = "AppleDynamicFramework";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleExecutableBinaryProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleExecutableBinaryProvider.java
index 910a940..c0745b7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleExecutableBinaryProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleExecutableBinaryProvider.java
@@ -16,7 +16,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 
 /**
@@ -30,7 +30,7 @@
  *       executable may avoid relinking symbols included in the loadable binary
  * </ul>
  */
-public final class AppleExecutableBinaryProvider extends Info {
+public final class AppleExecutableBinaryProvider extends NativeInfo {
 
   /** Skylark name for the AppleExecutableBinaryProvider. */
   public static final String SKYLARK_NAME = "AppleExecutableBinary";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleLoadableBundleBinaryProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleLoadableBundleBinaryProvider.java
index a8df0a8..c8da97c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleLoadableBundleBinaryProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleLoadableBundleBinaryProvider.java
@@ -16,7 +16,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 
 /**
@@ -27,7 +27,7 @@
  *   <li>'binary': The binary artifact output by apple_binary
  * </ul>
  */
-public final class AppleLoadableBundleBinaryProvider extends Info {
+public final class AppleLoadableBundleBinaryProvider extends NativeInfo {
 
   /** Skylark name for the AppleLoadableBundleBinary. */
   public static final String SKYLARK_NAME = "AppleLoadableBundleBinary";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibraryProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibraryProvider.java
index cc0f064..bbcafbc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibraryProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibraryProvider.java
@@ -16,7 +16,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 
 /**
@@ -32,7 +32,7 @@
  *       included in this archive multiple times).
  * </ul>
  */
-public final class AppleStaticLibraryProvider extends Info {
+public final class AppleStaticLibraryProvider extends NativeInfo {
 
   /** Skylark name for the AppleStaticLibraryProvider. */
   public static final String SKYLARK_NAME = "AppleStaticLibrary";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceProvider.java
index 8ad4575..3ca0b7d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceProvider.java
@@ -18,7 +18,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.rules.apple.DottedVersion;
 import com.google.devtools.build.lib.util.Preconditions;
@@ -27,7 +27,7 @@
 
 /** Provider that describes a simulator device. */
 @Immutable
-public final class IosDeviceProvider extends Info {
+public final class IosDeviceProvider extends NativeInfo {
   /** A builder of {@link IosDeviceProvider}s. */
   public static final class Builder {
     private String type;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
index 0778173..3658e22 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
@@ -29,7 +29,7 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.packages.NativeProvider.WithLegacySkylarkName;
 import com.google.devtools.build.lib.rules.cpp.CcLinkParamsInfo;
@@ -55,7 +55,7 @@
   category = SkylarkModuleCategory.PROVIDER,
   doc = "A provider for compilation and linking of objc."
 )
-public final class ObjcProvider extends Info {
+public final class ObjcProvider extends NativeInfo {
 
   /** Skylark name for the ObjcProvider. */
   public static final String SKYLARK_NAME = "objc";
@@ -494,11 +494,6 @@
     this.strictDependencyItems = Preconditions.checkNotNull(strictDependencyItems);
   }
 
-  @Override
-  public Concatter getConcatter() {
-    return null;
-  }
-
   /**
    * All artifacts, bundleable files, etc. of the type specified by {@code key}.
    */
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/XcTestAppProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/XcTestAppProvider.java
index a120925..8ebad53 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/XcTestAppProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/XcTestAppProvider.java
@@ -17,7 +17,7 @@
 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.Info;
+import com.google.devtools.build.lib.packages.NativeInfo;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.packages.NativeProvider.WithLegacySkylarkName;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -33,7 +33,7 @@
       "Deprecated. A provider for XCTest apps for testing. This is a legacy provider and should "
           + "not be used."
 )
-public final class XcTestAppProvider extends Info {
+public final class XcTestAppProvider extends NativeInfo {
   /**
    * The skylark struct key name for a rule implementation to use when exporting an ObjcProvider.
    */