Add a Binding type to the dagger.model package

Also move ContributionBinding.Kind to dagger.model.BindingKind

RELNOTES=n/a

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=180854144
diff --git a/java/dagger/internal/codegen/Binding.java b/java/dagger/internal/codegen/Binding.java
index ae2998b..e43b080 100644
--- a/java/dagger/internal/codegen/Binding.java
+++ b/java/dagger/internal/codegen/Binding.java
@@ -54,11 +54,7 @@
  * @author Gregory Kick
  * @since 2.0
  */
-abstract class Binding extends BindingDeclaration {
-
-  /** The {@link Key} that is provided by this binding. */
-  @Override
-  public abstract Key key();
+abstract class Binding extends BindingDeclaration implements dagger.model.Binding {
 
   /** The {@link BindingType} of this binding. */
   abstract BindingType bindingType();
@@ -93,7 +89,8 @@
    * union of {@link #explicitDependencies()} and {@link #implicitDependencies()}. This returns an
    * unmodifiable set.
    */
-  final ImmutableSet<DependencyRequest> dependencies() {
+  @Override
+  public ImmutableSet<DependencyRequest> dependencies() {
     return dependencies.get();
   }
 
@@ -242,10 +239,8 @@
    */
   abstract Optional<? extends Binding> unresolved();
 
-  /**
-   * The scope of this binding.
-   */
-  Optional<Scope> scope() {
+  @Override
+  public Optional<Scope> scope() {
     return Optional.empty();
   }
 
diff --git a/java/dagger/internal/codegen/BindingDeclarationFormatter.java b/java/dagger/internal/codegen/BindingDeclarationFormatter.java
index b97cec3..d47c59f 100644
--- a/java/dagger/internal/codegen/BindingDeclarationFormatter.java
+++ b/java/dagger/internal/codegen/BindingDeclarationFormatter.java
@@ -19,10 +19,10 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.Sets.immutableEnumSet;
 import static dagger.internal.codegen.ConfigurationAnnotations.getModuleSubcomponents;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_RELEASABLE_REFERENCE_MANAGER;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS;
 import static dagger.internal.codegen.DiagnosticFormatting.stripCommonTypePrefixes;
 import static dagger.internal.codegen.MoreAnnotationMirrors.simpleName;
+import static dagger.model.BindingKind.RELEASABLE_REFERENCE_MANAGER;
+import static dagger.model.BindingKind.RELEASABLE_REFERENCE_MANAGERS;
 import static javax.lang.model.type.TypeKind.DECLARED;
 import static javax.lang.model.type.TypeKind.EXECUTABLE;
 
@@ -31,6 +31,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import dagger.model.BindingKind;
 import javax.inject.Inject;
 import javax.lang.model.element.Element;
 import javax.lang.model.type.TypeKind;
@@ -43,10 +44,10 @@
   private static final ImmutableSet<TypeKind> FORMATTABLE_ELEMENT_TYPE_KINDS =
       immutableEnumSet(EXECUTABLE, DECLARED);
 
-  private static final ImmutableSet<ContributionBinding.Kind>
+  private static final ImmutableSet<BindingKind>
       FORMATTABLE_ELEMENTLESS_BINDING_KINDS =
           immutableEnumSet(
-              SYNTHETIC_RELEASABLE_REFERENCE_MANAGER, SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS);
+              RELEASABLE_REFERENCE_MANAGER, RELEASABLE_REFERENCE_MANAGERS);
 
   private final MethodSignatureFormatter methodSignatureFormatter;
 
@@ -61,8 +62,8 @@
    * <ul>
    * <li>Those with {@linkplain BindingDeclaration#bindingElement() binding elements} that are
    *     methods, constructors, or types.
-   * <li>{@link ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGER} bindings.
-   * <li>{@link ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS} bindings.
+   * <li>{@link BindingKind#RELEASABLE_REFERENCE_MANAGER} bindings.
+   * <li>{@link BindingKind#RELEASABLE_REFERENCE_MANAGERS} bindings.
    * </ul>
    */
   boolean canFormat(BindingDeclaration bindingDeclaration) {
@@ -75,7 +76,7 @@
     }
     if (bindingDeclaration instanceof ContributionBinding) {
       ContributionBinding contributionBinding = (ContributionBinding) bindingDeclaration;
-      return FORMATTABLE_ELEMENTLESS_BINDING_KINDS.contains(contributionBinding.bindingKind());
+      return FORMATTABLE_ELEMENTLESS_BINDING_KINDS.contains(contributionBinding.kind());
     }
     return false;
   }
@@ -88,12 +89,12 @@
 
     if (bindingDeclaration instanceof ContributionBinding) {
       ContributionBinding binding = (ContributionBinding) bindingDeclaration;
-      switch (binding.bindingKind()) {
-        case SYNTHETIC_RELEASABLE_REFERENCE_MANAGER:
+      switch (binding.kind()) {
+        case RELEASABLE_REFERENCE_MANAGER:
           return String.format(
               "binding for %s from the scope declaration",
               stripCommonTypePrefixes(binding.key().toString()));
-        case SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS:
+        case RELEASABLE_REFERENCE_MANAGERS:
           return String.format(
               "Dagger-generated binding for %s",
               stripCommonTypePrefixes(binding.key().toString()));
diff --git a/java/dagger/internal/codegen/BindingGraph.java b/java/dagger/internal/codegen/BindingGraph.java
index c81cb39..b0ab9d3 100644
--- a/java/dagger/internal/codegen/BindingGraph.java
+++ b/java/dagger/internal/codegen/BindingGraph.java
@@ -21,16 +21,17 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.any;
 import static com.google.common.collect.Iterables.isEmpty;
 import static dagger.internal.codegen.ComponentDescriptor.Kind.PRODUCTION_COMPONENT;
 import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
 import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod;
 import static dagger.internal.codegen.ComponentRequirement.Kind.BOUND_INSTANCE;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_KINDS;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_OPTIONAL_BINDING;
 import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
 import static dagger.internal.codegen.RequestKinds.getRequestKind;
 import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.model.BindingKind.OPTIONAL;
+import static dagger.model.BindingKind.SUBCOMPONENT_BUILDER;
 import static java.util.function.Predicate.isEqual;
 import static javax.lang.model.element.Modifier.ABSTRACT;
 import static javax.lang.model.util.ElementFilter.methodsIn;
@@ -55,7 +56,6 @@
 import dagger.internal.codegen.ComponentDescriptor.BuilderRequirementMethod;
 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodKind;
-import dagger.internal.codegen.ContributionBinding.Kind;
 import dagger.model.DependencyRequest;
 import dagger.model.Key;
 import dagger.model.RequestKind;
@@ -591,7 +591,7 @@
        * The queue will be used to detect which subcomponents need to be resolved.
        */
       private void addSubcomponentToOwningResolver(ProvisionBinding subcomponentBuilderBinding) {
-        checkArgument(subcomponentBuilderBinding.bindingKind().equals(Kind.SUBCOMPONENT_BUILDER));
+        checkArgument(subcomponentBuilderBinding.kind().equals(SUBCOMPONENT_BUILDER));
         Resolver owningResolver = getOwningResolver(subcomponentBuilderBinding).get();
 
         TypeElement builderType = MoreTypes.asTypeElement(subcomponentBuilderBinding.key().type());
@@ -1160,11 +1160,9 @@
          * at least one contribution declared within this component's modules.
          */
         private boolean hasLocalMultibindingContributions(ResolvedBindings resolvedBindings) {
-          return resolvedBindings
-                  .contributionBindings()
-                  .stream()
-                  .map(ContributionBinding::bindingKind)
-                  .anyMatch(SYNTHETIC_MULTIBOUND_KINDS::contains)
+          return any(
+                  resolvedBindings.contributionBindings(),
+                  ContributionBinding::isSyntheticMultibinding)
               && keysMatchingRequest(resolvedBindings.key())
                   .stream()
                   .anyMatch(key -> !getLocalExplicitMultibindings(key).isEmpty());
@@ -1178,8 +1176,8 @@
           return resolvedBindings
                   .contributionBindings()
                   .stream()
-                  .map(ContributionBinding::bindingKind)
-                  .anyMatch(isEqual(SYNTHETIC_OPTIONAL_BINDING))
+                  .map(ContributionBinding::kind)
+                  .anyMatch(isEqual(OPTIONAL))
               && !getLocalExplicitBindings(keyFactory.unwrapOptional(resolvedBindings.key()).get())
                   .isEmpty();
         }
diff --git a/java/dagger/internal/codegen/BindingGraphValidator.java b/java/dagger/internal/codegen/BindingGraphValidator.java
index b126f29..815d38d 100644
--- a/java/dagger/internal/codegen/BindingGraphValidator.java
+++ b/java/dagger/internal/codegen/BindingGraphValidator.java
@@ -29,10 +29,6 @@
 import static dagger.internal.codegen.ComponentRequirement.Kind.BOUND_INSTANCE;
 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentAnnotation;
 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
-import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
-import static dagger.internal.codegen.ContributionBinding.Kind.MEMBERS_INJECTOR;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_KINDS;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
 import static dagger.internal.codegen.ContributionBinding.indexMapBindingsByAnnotationType;
 import static dagger.internal.codegen.ContributionBinding.indexMapBindingsByMapKey;
 import static dagger.internal.codegen.DaggerElements.getAnnotationMirror;
@@ -71,6 +67,9 @@
 import static dagger.internal.codegen.Scopes.singletonScope;
 import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
 import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.MEMBERS_INJECTOR;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
 import static java.util.stream.Collectors.groupingBy;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.mapping;
@@ -101,6 +100,7 @@
 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
 import dagger.internal.codegen.ComponentRequirement.NullPolicy;
 import dagger.internal.codegen.ContributionType.HasContributionType;
+import dagger.model.BindingKind;
 import dagger.model.DependencyRequest;
 import dagger.model.Key;
 import dagger.model.RequestKind;
@@ -556,8 +556,8 @@
           incompatiblyScopedBindings.get(graph.componentDescriptor())) {
         message.append(ErrorMessages.INDENT);
 
-        switch (binding.bindingKind()) {
-          case SYNTHETIC_DELEGATE_BINDING:
+        switch (binding.kind()) {
+          case DELEGATE:
           case PROVISION:
             message.append(
                 methodSignatureFormatter.format(
@@ -631,7 +631,7 @@
         if (!dependencyRequest().isNullable() && binding.nullableType().isPresent()) {
           reportNullableBindingForNonNullableRequest(binding);
         }
-        if (binding.bindingKind().equals(INJECTION)) {
+        if (binding.kind().equals(INJECTION)) {
           TypeMirror type = binding.key().type();
           ValidationReport<TypeElement> report =
               injectValidator.validateType(MoreTypes.asTypeElement(type));
@@ -657,9 +657,9 @@
             }
           }
         }
-        if (binding.bindingKind().equals(SYNTHETIC_MULTIBOUND_MAP)) {
+        if (binding.kind().equals(MULTIBOUND_MAP)) {
           validateMapKeys(binding, owningComponent);
-        } else if (binding.bindingKind().equals(MEMBERS_INJECTOR)) {
+        } else if (binding.kind().equals(MEMBERS_INJECTOR)) {
           validateMembersInjectionType(binding);
         }
         super.visitContributionBinding(binding, owningComponent);
@@ -681,14 +681,14 @@
        * ContributionBinding}s with present {@linkplain BindingDeclaration#bindingElement() binding
        * elements}.
        *
-       * <p>Includes {@link ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGER} or
-       * {@link ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS} bindings, even
+       * <p>Includes {@link BindingKind#RELEASABLE_REFERENCE_MANAGER} or
+       * {@link BindingKind#RELEASABLE_REFERENCE_MANAGERS} bindings, even
        * though they have no binding elements, because they will be reported via the declared
        * scopes.
        *
        * <p>For other bindings without binding elements, such as the {@link
-       * ContributionBinding.Kind#SYNTHETIC_MULTIBOUND_KINDS}, includes the conflicting declarations
-       * in their resolved dependencies.
+       * ContributionBinding#isSyntheticMultibinding()}, includes the conflicting declarations in
+       * their resolved dependencies.
        */
       private ImmutableSetMultimap<ComponentDescriptor, BindingDeclaration>
           reportableDeclarations() {
@@ -746,7 +746,7 @@
       private void validateMapKeys(
           ContributionBinding binding, ComponentDescriptor owningComponent) {
         checkArgument(
-            binding.bindingKind().equals(SYNTHETIC_MULTIBOUND_MAP),
+            binding.kind().equals(MULTIBOUND_MAP),
             "binding must be a synthetic multibound map: %s",
             binding);
         ImmutableSet<ContributionBinding> multibindingContributions =
@@ -1012,9 +1012,8 @@
         if (resolvedBindings()
             .contributionBindings()
             .stream()
-            .map(ContributionBinding::bindingKind)
             // TODO(dpb): Kill with fire.
-            .anyMatch(SYNTHETIC_MULTIBOUND_KINDS::contains)) {
+            .anyMatch(ContributionBinding::isSyntheticMultibinding)) {
           reportMultipleContributionTypes();
           return;
         }
diff --git a/java/dagger/internal/codegen/BindingNetwork.java b/java/dagger/internal/codegen/BindingNetwork.java
index 2ac0697..a11c013 100644
--- a/java/dagger/internal/codegen/BindingNetwork.java
+++ b/java/dagger/internal/codegen/BindingNetwork.java
@@ -25,10 +25,10 @@
 import static com.google.common.graph.Graphs.inducedSubgraph;
 import static com.google.common.graph.Graphs.reachableNodes;
 import static com.google.common.graph.Graphs.transpose;
-import static dagger.internal.codegen.ContributionBinding.Kind.SUBCOMPONENT_BUILDER;
 import static dagger.internal.codegen.DaggerStreams.instancesOf;
 import static dagger.internal.codegen.DaggerStreams.toImmutableMap;
 import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.model.BindingKind.SUBCOMPONENT_BUILDER;
 
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.ImmutableMap;
@@ -435,7 +435,7 @@
         network.addNode(current);
         if (binding instanceof ContributionBinding) {
           ContributionBinding contributionBinding = (ContributionBinding) binding;
-          if (contributionBinding.bindingKind().equals(SUBCOMPONENT_BUILDER)) {
+          if (contributionBinding.kind().equals(SUBCOMPONENT_BUILDER)) {
             network.addEdge(
                 current,
                 subcomponentNode(contributionBinding, owningComponent),
@@ -456,7 +456,7 @@
 
       private ComponentNode subcomponentNode(
           ContributionBinding binding, ComponentDescriptor subcomponentParent) {
-        checkArgument(binding.bindingKind().equals(SUBCOMPONENT_BUILDER));
+        checkArgument(binding.kind().equals(SUBCOMPONENT_BUILDER));
         TypeElement builderType = asTypeElement(binding.key().type());
         TypeElement subcomponentType = asType(builderType.getEnclosingElement());
         ComponentTreePath childPath =
diff --git a/java/dagger/internal/codegen/ComponentBindingExpressions.java b/java/dagger/internal/codegen/ComponentBindingExpressions.java
index 7aa8541..cb0790d 100644
--- a/java/dagger/internal/codegen/ComponentBindingExpressions.java
+++ b/java/dagger/internal/codegen/ComponentBindingExpressions.java
@@ -23,16 +23,18 @@
 import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
 import static dagger.internal.codegen.BindingType.MEMBERS_INJECTION;
 import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
-import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_SET;
 import static dagger.internal.codegen.DaggerStreams.toImmutableList;
 import static dagger.internal.codegen.MemberSelect.staticMemberSelect;
 import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
 import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK;
 import static dagger.internal.codegen.TypeNames.REFERENCE_RELEASING_PROVIDER;
 import static dagger.internal.codegen.TypeNames.SINGLE_CHECK;
+import static dagger.model.BindingKind.COMPONENT;
+import static dagger.model.BindingKind.COMPONENT_DEPENDENCY;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.model.BindingKind.MULTIBOUND_SET;
+import static dagger.model.BindingKind.PROVISION;
 
 import com.google.auto.common.MoreTypes;
 import com.google.common.collect.HashBasedTable;
@@ -45,6 +47,7 @@
 import dagger.internal.MembersInjectors;
 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
 import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.model.BindingKind;
 import dagger.model.DependencyRequest;
 import dagger.model.Key;
 import dagger.model.RequestKind;
@@ -246,9 +249,9 @@
   /** Factory for building a {@link BindingExpression}. */
   private static final class BindingExpressionFactory {
     // TODO(user): Consider using PrivateMethodBindingExpression for other/all BEs?
-    private static final ImmutableSet<ContributionBinding.Kind> PRIVATE_METHOD_KINDS =
+    private static final ImmutableSet<BindingKind> PRIVATE_METHOD_KINDS =
         ImmutableSet.copyOf(
-            EnumSet.of(SYNTHETIC_MULTIBOUND_SET, SYNTHETIC_MULTIBOUND_MAP, INJECTION, PROVISION));
+            EnumSet.of(MULTIBOUND_SET, MULTIBOUND_MAP, INJECTION, PROVISION));
 
     private final BindingGraph graph;
     private final GeneratedComponentModel generatedComponentModel;
@@ -364,7 +367,7 @@
         ResolvedBindings resolvedBindings) {
       checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
       ContributionBinding binding = resolvedBindings.contributionBinding();
-      switch (binding.bindingKind()) {
+      switch (binding.kind()) {
         case COMPONENT:
           // The type parameter can be removed when we drop java 7 source support
           return () ->
@@ -402,27 +405,27 @@
               componentBindingExpressions,
               componentRequirementFields);
 
-        case SYNTHETIC_MULTIBOUND_SET:
+        case MULTIBOUND_SET:
           return new SetFactoryCreationExpression(
               binding, generatedComponentModel, componentBindingExpressions, graph);
 
-        case SYNTHETIC_MULTIBOUND_MAP:
+        case MULTIBOUND_MAP:
           return new MapFactoryCreationExpression(
               binding, generatedComponentModel, componentBindingExpressions, graph);
 
-        case SYNTHETIC_RELEASABLE_REFERENCE_MANAGER:
+        case RELEASABLE_REFERENCE_MANAGER:
           return new ReleasableReferenceManagerProviderCreationExpression(
               binding, generatedComponentModel, referenceReleasingManagerFields);
 
-        case SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS:
+        case RELEASABLE_REFERENCE_MANAGERS:
           return new ReleasableReferenceManagerSetProviderCreationExpression(
               binding, generatedComponentModel, referenceReleasingManagerFields, graph);
 
-        case SYNTHETIC_DELEGATE_BINDING:
+        case DELEGATE:
           return new DelegatingFrameworkInstanceCreationExpression(
               binding, generatedComponentModel, componentBindingExpressions);
 
-        case SYNTHETIC_OPTIONAL_BINDING:
+        case OPTIONAL:
           if (binding.explicitDependencies().isEmpty()) {
             return () -> optionalFactories.absentOptionalProvider(binding);
           } else {
@@ -516,7 +519,7 @@
         BindingExpression bindingExpression) {
       ProvisionBinding provisionBinding =
           (ProvisionBinding) bindingExpression.resolvedBindings().contributionBinding();
-      switch (provisionBinding.bindingKind()) {
+      switch (provisionBinding.kind()) {
         case COMPONENT:
           return new ComponentInstanceBindingExpression(
               bindingExpression, provisionBinding, generatedComponentModel.name(), types);
@@ -544,7 +547,7 @@
               subcomponentNames.get(bindingExpression.key()),
               types);
 
-        case SYNTHETIC_MULTIBOUND_SET:
+        case MULTIBOUND_SET:
           return new SetBindingExpression(
               provisionBinding,
               graph,
@@ -553,7 +556,7 @@
               types,
               elements);
 
-        case SYNTHETIC_MULTIBOUND_MAP:
+        case MULTIBOUND_MAP:
           return new MapBindingExpression(
               provisionBinding,
               graph,
@@ -562,11 +565,11 @@
               types,
               elements);
 
-        case SYNTHETIC_OPTIONAL_BINDING:
+        case OPTIONAL:
           return new OptionalBindingExpression(
               provisionBinding, bindingExpression, componentBindingExpressions, types);
 
-        case SYNTHETIC_DELEGATE_BINDING:
+        case DELEGATE:
           return DelegateBindingExpression.create(
               graph, bindingExpression, componentBindingExpressions, types, elements);
 
@@ -599,7 +602,7 @@
 
     private boolean usePrivateMethod(ContributionBinding binding) {
       return (!binding.scope().isPresent() || compilerOptions.experimentalAndroidMode())
-          && PRIVATE_METHOD_KINDS.contains(binding.bindingKind());
+          && PRIVATE_METHOD_KINDS.contains(binding.kind());
     }
 
     private boolean canUseSimpleMethod(ContributionBinding binding) {
diff --git a/java/dagger/internal/codegen/ComponentRequirement.java b/java/dagger/internal/codegen/ComponentRequirement.java
index 756a02d..38104fa 100644
--- a/java/dagger/internal/codegen/ComponentRequirement.java
+++ b/java/dagger/internal/codegen/ComponentRequirement.java
@@ -32,6 +32,7 @@
 import dagger.Binds;
 import dagger.BindsOptionalOf;
 import dagger.Provides;
+import dagger.model.BindingKind;
 import dagger.model.Key;
 import dagger.multibindings.Multibinds;
 import dagger.producers.Produces;
@@ -183,7 +184,7 @@
   }
 
   static ComponentRequirement forBoundInstance(ContributionBinding binding) {
-    checkArgument(binding.bindingKind().equals(ContributionBinding.Kind.BOUND_INSTANCE));
+    checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE));
     return forBoundInstance(
         binding.key(),
         binding.nullableType().isPresent(),
diff --git a/java/dagger/internal/codegen/ComponentRequirementProviderCreationExpression.java b/java/dagger/internal/codegen/ComponentRequirementProviderCreationExpression.java
index bc2bf17..c6c1746 100644
--- a/java/dagger/internal/codegen/ComponentRequirementProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/ComponentRequirementProviderCreationExpression.java
@@ -54,7 +54,7 @@
   }
 
   private ComponentRequirement componentRequirement() {
-    switch (binding.bindingKind()) {
+    switch (binding.kind()) {
       case COMPONENT_DEPENDENCY:
         return ComponentRequirement.forDependency(binding.key().type());
 
diff --git a/java/dagger/internal/codegen/ContributionBinding.java b/java/dagger/internal/codegen/ContributionBinding.java
index e790bc2..01a8ef7 100644
--- a/java/dagger/internal/codegen/ContributionBinding.java
+++ b/java/dagger/internal/codegen/ContributionBinding.java
@@ -16,7 +16,6 @@
 
 package dagger.internal.codegen;
 
-import static com.google.common.collect.Sets.immutableEnumSet;
 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.CLASS_CONSTRUCTOR;
 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.DELEGATE;
 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
@@ -29,20 +28,15 @@
 import com.google.auto.common.MoreTypes;
 import com.google.common.base.Equivalence;
 import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.Multimaps;
-import com.google.common.util.concurrent.ListenableFuture;
 import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.Component;
 import dagger.MapKey;
-import dagger.Provides;
 import dagger.internal.codegen.ContributionType.HasContributionType;
+import dagger.model.BindingKind;
 import dagger.model.Key;
-import dagger.producers.Produces;
 import java.util.Optional;
 import java.util.Set;
-import javax.inject.Inject;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
@@ -70,112 +64,6 @@
   }
 
   /**
-   * The kind of contribution this binding represents. Defines which elements can specify this kind
-   * of contribution.
-   */
-  enum Kind {
-    /**
-     * A synthetic binding for a multibound set that depends on the individual multibinding
-     * {@link Provides @Provides} or {@link Produces @Produces} methods.
-     */
-    SYNTHETIC_MULTIBOUND_SET,
-
-    /**
-     * A synthetic binding for a multibound map that depends on the individual multibinding
-     * {@link Provides @Provides} or {@link Produces @Produces} methods.
-     */
-    SYNTHETIC_MULTIBOUND_MAP,
-
-    /**
-     * A binding (provision or production) that delegates from requests for one key to another.
-     * These are the bindings that satisfy {@code @Binds} declarations.
-     */
-    SYNTHETIC_DELEGATE_BINDING,
-
-    /**
-     * A binding for a {@link dagger.releasablereferences.ReleasableReferenceManager} or {@link
-     * dagger.releasablereferences.TypedReleasableReferenceManager} object for a scope.
-     */
-    SYNTHETIC_RELEASABLE_REFERENCE_MANAGER,
-
-    /**
-     * A binding for a set of {@link dagger.releasablereferences.ReleasableReferenceManager} or
-     * {@link dagger.releasablereferences.TypedReleasableReferenceManager} objects.
-     */
-    SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS,
-
-    /**
-     * A synthetic binding for {@code Optional} of a type or a {@link javax.inject.Provider}, {@link
-     * dagger.Lazy}, or {@code Provider} of {@code Lazy} of a type. Generated by a {@link
-     * dagger.BindsOptionalOf} declaration.
-     */
-    SYNTHETIC_OPTIONAL_BINDING,
-
-    // Provision kinds
-
-    /** An {@link Inject}-annotated constructor. */
-    INJECTION,
-
-    /** A {@link Provides}-annotated method. */
-    PROVISION,
-
-    /** An implicit binding to a {@link Component @Component}-annotated type. */
-    COMPONENT,
-
-    /** A provision method on a component's {@linkplain Component#dependencies() dependency}. */
-    COMPONENT_PROVISION,
-
-    /** An instance of a {@linkplain Component#dependencies() dependency}. */
-    COMPONENT_DEPENDENCY,
-
-    /** A binding for a {@link dagger.MembersInjector} of a type. */
-    MEMBERS_INJECTOR,
-
-    /**
-     * A subcomponent builder method on a component or subcomponent.
-     */
-    SUBCOMPONENT_BUILDER,
-
-    /** A {@link dagger.BindsInstance @BindsInstance} builder method. */
-    BOUND_INSTANCE,
-
-    // Production kinds
-
-    /** A {@link Produces}-annotated method. */
-    PRODUCTION,
-
-    /**
-     * A production method on a production component's {@linkplain
-     * dagger.producers.ProductionComponent#dependencies()} dependency} that returns a
-     * {@link ListenableFuture}. Methods on production component dependencies that don't return a
-     * {@link ListenableFuture} are considered {@linkplain #PROVISION provision bindings}.
-     */
-    COMPONENT_PRODUCTION,
-    ;
-
-    static final ImmutableSet<Kind> SYNTHETIC_MULTIBOUND_KINDS =
-        immutableEnumSet(SYNTHETIC_MULTIBOUND_SET, SYNTHETIC_MULTIBOUND_MAP);
-
-    /**
-     * {@link #SYNTHETIC_MULTIBOUND_SET} or {@link #SYNTHETIC_MULTIBOUND_MAP}, depending on the key.
-     */
-    static Kind forMultibindingKey(Key key) {
-      if (SetType.isSet(key)) {
-        return SYNTHETIC_MULTIBOUND_SET;
-      } else if (MapType.isMap(key)) {
-        return SYNTHETIC_MULTIBOUND_MAP;
-      } else {
-        throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key));
-      }
-    }
-  }
-
-  /**
-   * The kind of this contribution binding.
-   */
-  protected abstract Kind bindingKind();
-
-  /**
    * {@code true} if {@link #contributingModule()} is present and this is a nonabstract instance
    * method.
    */
@@ -194,6 +82,11 @@
         .filter(type -> type.getKind().isPrimitive());
   }
 
+  @Override
+  public final boolean isNullable() {
+    return nullableType().isPresent();
+  }
+
   /**
    * The strategy for getting an instance of a factory for a {@link ContributionBinding}.
    */
@@ -217,16 +110,16 @@
    * <p>All other bindings use the {@link FactoryCreationStrategy#CLASS_CONSTRUCTOR} strategy.
    */
   FactoryCreationStrategy factoryCreationStrategy() {
-    switch (bindingKind()) {
-      case SYNTHETIC_DELEGATE_BINDING:
+    switch (kind()) {
+      case DELEGATE:
         return DELEGATE;
       case PROVISION:
         return dependencies().isEmpty() && !requiresModuleInstance()
             ? SINGLETON_INSTANCE
             : CLASS_CONSTRUCTOR;
       case INJECTION:
-      case SYNTHETIC_MULTIBOUND_SET:
-      case SYNTHETIC_MULTIBOUND_MAP:
+      case MULTIBOUND_SET:
+      case MULTIBOUND_MAP:
         return dependencies().isEmpty() ? SINGLETON_INSTANCE : CLASS_CONSTRUCTOR;
       default:
         return CLASS_CONSTRUCTOR;
@@ -252,6 +145,32 @@
     }
   }
 
+  final boolean isSyntheticMultibinding() {
+    switch (kind()) {
+      case MULTIBOUND_SET:
+      case MULTIBOUND_MAP:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * Returns {@link BindingKind#MULTIBOUND_SET} or {@link
+   * BindingKind#MULTIBOUND_MAP} if the key is a set or map.
+   *
+   * @throws IllegalArgumentException if {@code key} is neither a set nor a map
+   */
+  static BindingKind bindingKindForMultibindingKey(Key key) {
+    if (SetType.isSet(key)) {
+      return BindingKind.MULTIBOUND_SET;
+    } else if (MapType.isMap(key)) {
+      return BindingKind.MULTIBOUND_MAP;
+    } else {
+      throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key));
+    }
+  }
+
   /**
    * Indexes map-multibindings by map key (the result of calling
    * {@link AnnotationValue#getValue()} on a single member or the whole {@link AnnotationMirror}
@@ -298,6 +217,6 @@
 
     abstract B wrappedMapKey(Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKey);
 
-    abstract B bindingKind(ContributionBinding.Kind kind);
+    abstract B kind(BindingKind kind);
   }
 }
diff --git a/java/dagger/internal/codegen/FactoryGenerator.java b/java/dagger/internal/codegen/FactoryGenerator.java
index da77364..6e925ae 100644
--- a/java/dagger/internal/codegen/FactoryGenerator.java
+++ b/java/dagger/internal/codegen/FactoryGenerator.java
@@ -26,8 +26,6 @@
 import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.DELEGATE;
 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
-import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
-import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION;
 import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD;
 import static dagger.internal.codegen.GwtCompatibility.gwtIncompatibleAnnotation;
 import static dagger.internal.codegen.MapKeys.mapKeyFactoryMethod;
@@ -37,6 +35,8 @@
 import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
 import static dagger.internal.codegen.SourceFiles.parameterizedGeneratedTypeNameForBinding;
 import static dagger.internal.codegen.TypeNames.factoryOf;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.PROVISION;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PRIVATE;
 import static javax.lang.model.element.Modifier.PUBLIC;
@@ -227,7 +227,7 @@
         makeParametersCodeBlock(
             frameworkFieldUsages(binding.provisionDependencies(), frameworkFields).values());
 
-    if (binding.bindingKind().equals(PROVISION)) {
+    if (binding.kind().equals(PROVISION)) {
       // TODO(dpb): take advantage of the code in InjectionMethods so this doesn't have to be
       // duplicated
       binding
@@ -279,7 +279,7 @@
 
   private static ImmutableList<TypeVariableName> typeParameters(ProvisionBinding binding) {
     // Use type parameters from the injected type or the module instance *only* if we require it.
-    if (binding.bindingKind().equals(INJECTION) || binding.requiresModuleInstance()) {
+    if (binding.kind().equals(INJECTION) || binding.requiresModuleInstance()) {
       return bindingTypeElementTypeVariableNames(binding);
     }
     return ImmutableList.of();
diff --git a/java/dagger/internal/codegen/FrameworkField.java b/java/dagger/internal/codegen/FrameworkField.java
index 9c220ba..88d1c49 100644
--- a/java/dagger/internal/codegen/FrameworkField.java
+++ b/java/dagger/internal/codegen/FrameworkField.java
@@ -16,7 +16,7 @@
 
 package dagger.internal.codegen;
 
-import static dagger.internal.codegen.ContributionBinding.Kind.MEMBERS_INJECTOR;
+import static dagger.model.BindingKind.MEMBERS_INJECTOR;
 
 import com.google.auto.value.AutoValue;
 import com.google.common.base.CaseFormat;
@@ -97,7 +97,7 @@
       ContributionBinding binding = resolvedBindings.contributionBinding();
       if (binding.bindingElement().isPresent()) {
         String name = BINDING_ELEMENT_NAME.visit(binding.bindingElement().get(), binding);
-        return binding.bindingKind().equals(MEMBERS_INJECTOR)
+        return binding.kind().equals(MEMBERS_INJECTOR)
             ? name + "MembersInjector"
             : name;
       }
diff --git a/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java b/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
index eb8cf7c..5f52f22 100644
--- a/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
@@ -18,8 +18,8 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
 import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.model.BindingKind.INJECTION;
 
 import com.google.common.collect.Lists;
 import com.squareup.javapoet.CodeBlock;
@@ -75,7 +75,7 @@
 
     // When scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the
     // type properly, so cast to a raw framework type before scoping.
-    if (binding.bindingKind().equals(INJECTION)
+    if (binding.kind().equals(INJECTION)
         && binding.unresolved().isPresent()
         && binding.scope().isPresent()) {
       return CodeBlocks.cast(createFactory, binding.bindingType().frameworkClass());
diff --git a/java/dagger/internal/codegen/MapBindingExpression.java b/java/dagger/internal/codegen/MapBindingExpression.java
index e944b3c..150bdae 100644
--- a/java/dagger/internal/codegen/MapBindingExpression.java
+++ b/java/dagger/internal/codegen/MapBindingExpression.java
@@ -20,14 +20,15 @@
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
 import static dagger.internal.codegen.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
 import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import dagger.internal.MapBuilder;
+import dagger.model.BindingKind;
 import dagger.model.DependencyRequest;
 import java.util.Collections;
 import java.util.Map;
@@ -52,8 +53,8 @@
       DaggerTypes types,
       Elements elements) {
     super(delegate, types);
-    ContributionBinding.Kind bindingKind = binding.bindingKind();
-    checkArgument(bindingKind.equals(SYNTHETIC_MULTIBOUND_MAP), bindingKind);
+    BindingKind bindingKind = binding.kind();
+    checkArgument(bindingKind.equals(MULTIBOUND_MAP), bindingKind);
     this.binding = binding;
     this.componentBindingExpressions = componentBindingExpressions;
     this.elements = elements;
diff --git a/java/dagger/internal/codegen/MemberSelect.java b/java/dagger/internal/codegen/MemberSelect.java
index cd440d5..43232d5 100644
--- a/java/dagger/internal/codegen/MemberSelect.java
+++ b/java/dagger/internal/codegen/MemberSelect.java
@@ -96,11 +96,11 @@
     ContributionBinding contributionBinding = resolvedBindings.contributionBinding();
     if (contributionBinding.factoryCreationStrategy().equals(SINGLETON_INSTANCE)
         && !contributionBinding.scope().isPresent()) {
-      switch (contributionBinding.bindingKind()) {
-        case SYNTHETIC_MULTIBOUND_MAP:
+      switch (contributionBinding.kind()) {
+        case MULTIBOUND_MAP:
           return Optional.of(emptyMapFactory(contributionBinding));
 
-        case SYNTHETIC_MULTIBOUND_SET:
+        case MULTIBOUND_SET:
           return Optional.of(emptySetFactory(contributionBinding));
 
         case INJECTION:
diff --git a/java/dagger/internal/codegen/MembersInjectionBinding.java b/java/dagger/internal/codegen/MembersInjectionBinding.java
index 89127d4..3589321 100644
--- a/java/dagger/internal/codegen/MembersInjectionBinding.java
+++ b/java/dagger/internal/codegen/MembersInjectionBinding.java
@@ -33,6 +33,7 @@
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.SetMultimap;
+import dagger.model.BindingKind;
 import dagger.model.DependencyRequest;
 import dagger.model.Key;
 import java.util.ArrayList;
@@ -65,7 +66,7 @@
 @AutoValue
 abstract class MembersInjectionBinding extends Binding {
   @Override
-  Optional<? extends Element> bindingElement() {
+  public Optional<TypeElement> bindingElement() {
     return Optional.of(membersInjectedType());
   }
 
@@ -75,7 +76,7 @@
   abstract Optional<MembersInjectionBinding> unresolved();
 
   @Override
-  Optional<TypeElement> contributingModule() {
+  public Optional<TypeElement> contributingModule() {
     return Optional.empty();
   }
 
@@ -89,10 +90,20 @@
   abstract Optional<Key> parentKey();
 
   @Override
-  public BindingType bindingType() {
+  BindingType bindingType() {
     return BindingType.MEMBERS_INJECTION;
   }
 
+  @Override
+  public BindingKind kind() {
+    return BindingKind.MEMBERS_INJECTION;
+  }
+
+  @Override
+  public boolean isNullable() {
+    return false;
+  }
+
   /**
    * Returns {@code true} if any of this binding's injection sites are directly on the bound type.
    */
@@ -104,6 +115,11 @@
                 injectionSite.element().getEnclosingElement().equals(membersInjectedType()));
   }
 
+  @Override
+  public final boolean isProduction() {
+    return false;
+  }
+
   @AutoValue
   abstract static class InjectionSite {
     enum Kind {
diff --git a/java/dagger/internal/codegen/ProductionBinding.java b/java/dagger/internal/codegen/ProductionBinding.java
index 5d827fb..4e96655 100644
--- a/java/dagger/internal/codegen/ProductionBinding.java
+++ b/java/dagger/internal/codegen/ProductionBinding.java
@@ -22,6 +22,10 @@
 import static dagger.internal.codegen.DaggerTypes.isFutureType;
 import static dagger.internal.codegen.MapKeys.getMapKey;
 import static dagger.internal.codegen.MoreAnnotationMirrors.wrapOptionalInEquivalence;
+import static dagger.model.BindingKind.COMPONENT_PRODUCTION;
+import static dagger.model.BindingKind.DELEGATE;
+import static dagger.model.BindingKind.OPTIONAL;
+import static dagger.model.BindingKind.PRODUCTION;
 import static javax.lang.model.element.ElementKind.METHOD;
 
 import com.google.auto.common.MoreTypes;
@@ -110,6 +114,11 @@
         .thrownTypes(ImmutableList.<TypeMirror>of());
   }
 
+  @Override
+  public final boolean isProduction() {
+    return true;
+  }
+
   @AutoValue.Builder
   @CanIgnoreReturnValue
   abstract static class Builder extends ContributionBinding.Builder<Builder> {
@@ -173,7 +182,7 @@
           .key(key)
           .explicitDependencies(dependencies)
           .wrappedMapKey(wrapOptionalInEquivalence(getMapKey(producesMethod)))
-          .bindingKind(Kind.PRODUCTION)
+          .kind(PRODUCTION)
           .productionKind(productionKind)
           .thrownTypes(producesMethod.getThrownTypes())
           .executorRequest(executorRequest)
@@ -194,7 +203,7 @@
           .key(key)
           .explicitDependencies(
               dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions))
-          .bindingKind(Kind.forMultibindingKey(key))
+          .kind(bindingKindForMultibindingKey(key))
           .build();
     }
 
@@ -207,7 +216,7 @@
           .contributionType(ContributionType.UNIQUE)
           .bindingElement(componentMethod)
           .key(keyFactory.forProductionComponentMethod(componentMethod))
-          .bindingKind(Kind.COMPONENT_PRODUCTION)
+          .kind(COMPONENT_PRODUCTION)
           .thrownTypes(componentMethod.getThrownTypes())
           .build();
     }
@@ -222,7 +231,7 @@
           .explicitDependencies(delegateDeclaration.delegateRequest())
           .nullableType(delegateBinding.nullableType())
           .wrappedMapKey(delegateDeclaration.wrappedMapKey())
-          .bindingKind(Kind.SYNTHETIC_DELEGATE_BINDING)
+          .kind(DELEGATE)
           .build();
     }
 
@@ -234,7 +243,7 @@
       return ProductionBinding.builder()
           .contributionType(ContributionType.UNIQUE)
           .key(key)
-          .bindingKind(Kind.SYNTHETIC_OPTIONAL_BINDING)
+          .kind(OPTIONAL)
           .explicitDependencies(
               dependencyRequestFactory.forSyntheticPresentOptionalBinding(key, kind))
           .build();
diff --git a/java/dagger/internal/codegen/ProvisionBinding.java b/java/dagger/internal/codegen/ProvisionBinding.java
index 4cb7107..9b46da2 100644
--- a/java/dagger/internal/codegen/ProvisionBinding.java
+++ b/java/dagger/internal/codegen/ProvisionBinding.java
@@ -26,6 +26,18 @@
 import static dagger.internal.codegen.MapKeys.getMapKey;
 import static dagger.internal.codegen.MoreAnnotationMirrors.wrapOptionalInEquivalence;
 import static dagger.internal.codegen.Scopes.uniqueScopeOf;
+import static dagger.model.BindingKind.BOUND_INSTANCE;
+import static dagger.model.BindingKind.COMPONENT;
+import static dagger.model.BindingKind.COMPONENT_DEPENDENCY;
+import static dagger.model.BindingKind.COMPONENT_PROVISION;
+import static dagger.model.BindingKind.DELEGATE;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.MEMBERS_INJECTOR;
+import static dagger.model.BindingKind.OPTIONAL;
+import static dagger.model.BindingKind.PROVISION;
+import static dagger.model.BindingKind.RELEASABLE_REFERENCE_MANAGER;
+import static dagger.model.BindingKind.RELEASABLE_REFERENCE_MANAGERS;
+import static dagger.model.BindingKind.SUBCOMPONENT_BUILDER;
 import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
 import static javax.lang.model.element.ElementKind.METHOD;
 
@@ -40,6 +52,7 @@
 import com.google.errorprone.annotations.CheckReturnValue;
 import dagger.internal.codegen.ComponentDescriptor.BuilderRequirementMethod;
 import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.model.BindingKind;
 import dagger.model.DependencyRequest;
 import dagger.model.Key;
 import dagger.model.RequestKind;
@@ -89,8 +102,8 @@
   }
 
   /**
-   * {@link InjectionSite}s for all {@code @Inject} members if {@link #bindingKind()} is {@link
-   * ContributionBinding.Kind#INJECTION}, otherwise empty.
+   * {@link InjectionSite}s for all {@code @Inject} members if {@link #kind()} is {@link
+   * BindingKind#INJECTION}, otherwise empty.
    */
   abstract ImmutableSortedSet<InjectionSite> injectionSites();
 
@@ -102,8 +115,10 @@
   @Override
   abstract Optional<ProvisionBinding> unresolved();
 
+  // TODO(ronshapiro): we should be able to remove this, but AutoValue barks on the Builder's scope
+  // method, saying that the method doesn't correspond to a property of ProvisionBinding
   @Override
-  abstract Optional<Scope> scope();
+  public abstract Optional<Scope> scope();
 
   private static Builder builder() {
     return new AutoValue_ProvisionBinding.Builder()
@@ -113,17 +128,21 @@
 
   abstract Builder toBuilder();
 
-  private static final ImmutableSet<ContributionBinding.Kind> KINDS_TO_CHECK_FOR_NULL =
-      ImmutableSet.of(
-          ContributionBinding.Kind.PROVISION, ContributionBinding.Kind.COMPONENT_PROVISION);
+  private static final ImmutableSet<BindingKind> KINDS_TO_CHECK_FOR_NULL =
+      ImmutableSet.of(PROVISION, COMPONENT_PROVISION);
 
   boolean shouldCheckForNull(CompilerOptions compilerOptions) {
-    return KINDS_TO_CHECK_FOR_NULL.contains(bindingKind())
+    return KINDS_TO_CHECK_FOR_NULL.contains(kind())
         && !contributedPrimitiveType().isPresent()
         && !nullableType().isPresent()
         && compilerOptions.doCheckForNulls();
   }
 
+  @Override
+  public final boolean isProduction() {
+    return false;
+  }
+
   @AutoValue.Builder
   @CanIgnoreReturnValue
   abstract static class Builder extends ContributionBinding.Builder<Builder> {
@@ -203,7 +222,7 @@
               .key(key)
               .provisionDependencies(provisionDependencies)
               .injectionSites(injectionSites)
-              .bindingKind(Kind.INJECTION)
+              .kind(INJECTION)
               .scope(uniqueScopeOf(constructorElement.getEnclosingElement()));
 
       TypeElement bindingTypeElement =
@@ -233,7 +252,7 @@
           .provisionDependencies(dependencies)
           .nullableType(ConfigurationAnnotations.getNullableType(providesMethod))
           .wrappedMapKey(wrapOptionalInEquivalence(getMapKey(providesMethod)))
-          .bindingKind(Kind.PROVISION)
+          .kind(PROVISION)
           .scope(uniqueScopeOf(providesMethod))
           .build();
     }
@@ -251,7 +270,7 @@
           .key(key)
           .provisionDependencies(
               dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions))
-          .bindingKind(Kind.forMultibindingKey(key))
+          .kind(bindingKindForMultibindingKey(key))
           .build();
     }
 
@@ -261,7 +280,7 @@
           .contributionType(ContributionType.UNIQUE)
           .bindingElement(componentDefinitionType)
           .key(keyFactory.forType(componentDefinitionType.asType()))
-          .bindingKind(Kind.COMPONENT)
+          .kind(COMPONENT)
           .build();
     }
 
@@ -271,7 +290,7 @@
           .contributionType(ContributionType.UNIQUE)
           .bindingElement(dependency.typeElement())
           .key(keyFactory.forType(dependency.type()))
-          .bindingKind(Kind.COMPONENT_DEPENDENCY)
+          .kind(COMPONENT_DEPENDENCY)
           .build();
     }
 
@@ -284,7 +303,7 @@
           .bindingElement(componentMethod)
           .key(keyFactory.forComponentMethod(componentMethod))
           .nullableType(ConfigurationAnnotations.getNullableType(componentMethod))
-          .bindingKind(Kind.COMPONENT_PROVISION)
+          .kind(COMPONENT_PROVISION)
           .scope(uniqueScopeOf(componentMethod))
           .build();
     }
@@ -301,7 +320,7 @@
           .bindingElement(builderMethod)
           .key(method.requirement().key().get())
           .nullableType(ConfigurationAnnotations.getNullableType(parameterElement))
-          .bindingKind(Kind.BOUND_INSTANCE)
+          .kind(BOUND_INSTANCE)
           .build();
     }
 
@@ -316,7 +335,7 @@
           .bindingElement(subcomponentBuilderMethod)
           .key(
               keyFactory.forSubcomponentBuilderMethod(subcomponentBuilderMethod, declaredContainer))
-          .bindingKind(Kind.SUBCOMPONENT_BUILDER)
+          .kind(SUBCOMPONENT_BUILDER)
           .build();
     }
 
@@ -326,7 +345,7 @@
       return ProvisionBinding.builder()
           .contributionType(ContributionType.UNIQUE)
           .key(subcomponentDeclaration.key())
-          .bindingKind(Kind.SUBCOMPONENT_BUILDER)
+          .kind(SUBCOMPONENT_BUILDER)
           .build();
     }
 
@@ -351,7 +370,7 @@
           .key(keyFactory.forDelegateBinding(delegateDeclaration, Provider.class))
           .provisionDependencies(delegateDeclaration.delegateRequest())
           .wrappedMapKey(delegateDeclaration.wrappedMapKey())
-          .bindingKind(Kind.SYNTHETIC_DELEGATE_BINDING)
+          .kind(DELEGATE)
           .scope(uniqueScopeOf(delegateDeclaration.bindingElement().get()));
     }
 
@@ -363,7 +382,7 @@
       return ProvisionBinding.builder()
           .contributionType(ContributionType.UNIQUE)
           .key(keyFactory.forReleasableReferenceManager(scope))
-          .bindingKind(Kind.SYNTHETIC_RELEASABLE_REFERENCE_MANAGER)
+          .kind(RELEASABLE_REFERENCE_MANAGER)
           .build();
     }
 
@@ -385,7 +404,7 @@
       return ProvisionBinding.builder()
           .contributionType(ContributionType.UNIQUE)
           .key(keyFactory.forSetOfReleasableReferenceManagers())
-          .bindingKind(Kind.SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS)
+          .kind(RELEASABLE_REFERENCE_MANAGERS)
           .build();
     }
 
@@ -407,7 +426,7 @@
       return ProvisionBinding.builder()
           .contributionType(ContributionType.UNIQUE)
           .key(key)
-          .bindingKind(Kind.SYNTHETIC_OPTIONAL_BINDING)
+          .kind(OPTIONAL)
           .build();
     }
 
@@ -428,7 +447,7 @@
       return ProvisionBinding.builder()
           .key(key)
           .contributionType(ContributionType.UNIQUE)
-          .bindingKind(Kind.MEMBERS_INJECTOR)
+          .kind(MEMBERS_INJECTOR)
           .bindingElement(MoreTypes.asTypeElement(membersInjectionBinding.key().type()))
           .provisionDependencies(membersInjectionBinding.dependencies())
           .injectionSites(membersInjectionBinding.injectionSites())
diff --git a/java/dagger/internal/codegen/SourceFiles.java b/java/dagger/internal/codegen/SourceFiles.java
index 9e27003..782a872 100644
--- a/java/dagger/internal/codegen/SourceFiles.java
+++ b/java/dagger/internal/codegen/SourceFiles.java
@@ -21,9 +21,6 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.base.Verify.verify;
-import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_SET;
 import static dagger.internal.codegen.DaggerStreams.toImmutableList;
 import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
 import static dagger.internal.codegen.Optionals.optionalComparator;
@@ -37,6 +34,9 @@
 import static dagger.internal.codegen.TypeNames.SET_FACTORY;
 import static dagger.internal.codegen.TypeNames.SET_OF_PRODUCED_PRODUCER;
 import static dagger.internal.codegen.TypeNames.SET_PRODUCER;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.model.BindingKind.MULTIBOUND_SET;
 import static java.util.Comparator.comparing;
 import static javax.lang.model.SourceVersion.isName;
 
@@ -189,7 +189,7 @@
         ContributionBinding contribution = (ContributionBinding) binding;
         checkArgument(contribution.bindingTypeElement().isPresent());
         ClassName enclosingClassName = ClassName.get(contribution.bindingTypeElement().get());
-        switch (contribution.bindingKind()) {
+        switch (contribution.kind()) {
           case INJECTION:
           case PROVISION:
           case PRODUCTION:
@@ -256,7 +256,7 @@
    * </ul>
    */
   static ClassName setFactoryClassName(ContributionBinding binding) {
-    checkArgument(binding.bindingKind().equals(SYNTHETIC_MULTIBOUND_SET));
+    checkArgument(binding.kind().equals(MULTIBOUND_SET));
     if (binding.bindingType().equals(BindingType.PROVISION)) {
       return SET_FACTORY;
     } else {
@@ -267,7 +267,7 @@
 
   /** The {@link java.util.Map} factory class name appropriate for map bindings. */
   static ClassName mapFactoryClassName(ContributionBinding binding) {
-    checkState(binding.bindingKind().equals(SYNTHETIC_MULTIBOUND_MAP), binding.bindingKind());
+    checkState(binding.kind().equals(MULTIBOUND_MAP), binding.kind());
     MapType mapType = MapType.from(binding.key());
     switch (binding.bindingType()) {
       case PROVISION:
@@ -284,7 +284,7 @@
   }
 
   private static String factoryPrefix(ContributionBinding binding) {
-    switch (binding.bindingKind()) {
+    switch (binding.kind()) {
       case INJECTION:
         return "";
 
@@ -301,7 +301,7 @@
   static ImmutableList<TypeVariableName> bindingTypeElementTypeVariableNames(Binding binding) {
     if (binding instanceof ContributionBinding) {
       ContributionBinding contributionBinding = (ContributionBinding) binding;
-      if (!contributionBinding.bindingKind().equals(INJECTION)
+      if (!contributionBinding.kind().equals(INJECTION)
           && !contributionBinding.requiresModuleInstance()) {
         return ImmutableList.of();
       }
diff --git a/java/dagger/internal/codegen/SubcomponentDeclaration.java b/java/dagger/internal/codegen/SubcomponentDeclaration.java
index 1d17e59..dad6bbe 100644
--- a/java/dagger/internal/codegen/SubcomponentDeclaration.java
+++ b/java/dagger/internal/codegen/SubcomponentDeclaration.java
@@ -45,7 +45,7 @@
   public abstract Key key();
 
   @Override
-  abstract Optional<? extends ExecutableElement> bindingElement();
+  abstract Optional<ExecutableElement > bindingElement();
 
   /**
    * The type element that defines the {@link dagger.Subcomponent} or {@link
diff --git a/java/dagger/model/Binding.java b/java/dagger/model/Binding.java
new file mode 100644
index 0000000..38a4527
--- /dev/null
+++ b/java/dagger/model/Binding.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * 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 dagger.model;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.DoNotMock;
+import java.util.Optional;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * The association between a {@link Key} and the way in which instances of the key are provided.
+ * Includes any {@linkplain DependencyRequest dependencies} that are needed in order to provide the
+ * instances.
+ */
+@DoNotMock("Equality semantics are important but not specified, so use only Dagger implementations")
+public interface Binding {
+  /** The binding's key. */
+  Key key();
+
+  /**
+   * The dependencies of this binding. The order of the dependencies corresponds to the order in
+   * which they will be injected when the binding is requested.
+   */
+  ImmutableSet<DependencyRequest> dependencies();
+
+  /**
+   * The {@link Element} that declares this binding. Absent for {@linkplain BindingKind binding
+   * kinds} that are not always declared by exactly one element.
+   *
+   * <p>For example, consider {@link BindingKind#MULTIBOUND_SET}. A component with many
+   * {@code @IntoSet} bindings for the same key will have a synthetic binding that depends on all
+   * contributions, but with no identifiying binding element. A {@code @Multibinds} method will also
+   * contribute a synthetic binding, but since multiple {@code @Multibinds} methods can coexist in
+   * the same component (and contribute to one single binding), it has no binding element.
+   */
+  // TODO(ronshapiro): examine whether this wildcard+bound have any benefit. In the processor code,
+  // we never actually refer to the overridden bindingElement methods directly in a way which needs
+  // anything more than an Element. Removing the wildcard would allow for simpler user-written code
+  // when the binding element is passed to a method.
+  Optional<? extends Element> bindingElement();
+
+  /**
+   * The {@link TypeElement} of the module which contributes this binding. Absent for bindings that
+   * have no {@link #bindingElement() binding element}.
+   */
+  Optional<TypeElement> contributingModule();
+
+  /** The scope of this binding if it has one. */
+  Optional<Scope> scope();
+
+  /**
+   * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link
+   * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable()
+   * non-nullable dependency requests}.
+   */
+  boolean isNullable();
+
+  /** Returns {@code true} if this is a production binding, e.g. an {@code @Produces} method. */
+  boolean isProduction();
+
+  /** The kind of binding this instance represents. */
+  BindingKind kind();
+}
diff --git a/java/dagger/model/BindingKind.java b/java/dagger/model/BindingKind.java
new file mode 100644
index 0000000..6bcdb57
--- /dev/null
+++ b/java/dagger/model/BindingKind.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * 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 dagger.model;
+
+/** Represents the different kinds of {@link Binding}s that can exist in a binding graph. */
+public enum BindingKind {
+  /** A binding for an {@link javax.inject.Inject}-annotated constructor. */
+  INJECTION,
+
+  /** A binding for a {@link dagger.Provides}-annotated method. */
+  PROVISION,
+
+  /**
+   * An implicit binding for a {@link dagger.Component}- or {@link
+   * dagger.producers.ProductionComponent}-annotated type.
+   */
+  COMPONENT,
+
+  /**
+   * A binding for a provision method on a component's {@linkplain dagger.Component#dependencies()
+   * dependency}.
+   */
+  COMPONENT_PROVISION,
+
+  /**
+   * A binding for an instance of a component's {@linkplain dagger.Component#dependencies()
+   * dependency}.
+   */
+  COMPONENT_DEPENDENCY,
+
+  /** A binding for a {@link dagger.MembersInjector} of a type. */
+  MEMBERS_INJECTOR,
+
+  /** A binding for a subcomponent builder. */
+  SUBCOMPONENT_BUILDER,
+
+  /** A binding for a {@link dagger.BindsInstance}-annotated builder method. */
+  BOUND_INSTANCE,
+
+  /** A binding for a {@link dagger.producers.Produces}-annotated method. */
+  PRODUCTION,
+
+  /**
+   * A binding for a production method on a production component's {@linkplain
+   * dagger.producers.ProductionComponent#dependencies()} dependency} that returns a {@link
+   * com.google.common.util.concurrent.ListenableFuture} or {@link
+   * com.google.common.util.concurrent.FluentFuture}. Methods on production component dependencies
+   * that don't return a future are considered {@linkplain #COMPONENT_PROVISION component provision
+   * bindings}.
+   */
+  COMPONENT_PRODUCTION,
+
+  /**
+   * A synthetic binding for a multibound set that depends on individual multibinding {@link
+   * #PROVISION} or {@link #PRODUCTION} contributions.
+   */
+  MULTIBOUND_SET,
+
+  /**
+   * A synthetic binding for a multibound map that depends on the individual multibinding {@link
+   * #PROVISION} or {@link #PRODUCTION} contributions.
+   */
+  MULTIBOUND_MAP,
+
+  /**
+   * A synthetic binding for {@code Optional} of a type or a {@link javax.inject.Provider}, {@link
+   * dagger.Lazy}, or {@code Provider} of {@code Lazy} of a type. Generated by a {@link
+   * dagger.BindsOptionalOf} declaration.
+   */
+  OPTIONAL,
+
+  /**
+   * A binding for a {@link dagger.releasablereferences.ReleasableReferenceManager} or {@link
+   * dagger.releasablereferences.TypedReleasableReferenceManager} object for a scope.
+   */
+  RELEASABLE_REFERENCE_MANAGER,
+
+  /**
+   * A binding for a set of {@link dagger.releasablereferences.ReleasableReferenceManager} or {@link
+   * dagger.releasablereferences.TypedReleasableReferenceManager} objects.
+   */
+  RELEASABLE_REFERENCE_MANAGERS,
+
+  /**
+   * A binding for {@link dagger.Binds}-annotated method that that delegates from requests for one
+   * key to another.
+   */
+  // TODO(dpb,ronshapiro): This name is confusing and could use work. Not all usages of @Binds
+  // bindings are simple delegations and we should have a name that better reflects that
+  DELEGATE,
+
+  /** A binding for a members injection method on a component. */
+  MEMBERS_INJECTION,
+  ;
+}