Remove unused framework fields

In the process, merge RequestFulfillment into BindingExpression. Without this, RequestFulfillments would need to know about BindingExpressions (to call maybeInitializeField), and BindingExpressions would need to know about their RequestFulfillment's (via requestFulfillmentDelgate). This combines both concepts and makes BindingExpression the core type.

Notably, lots of the code in BindingExpression is moved into FrameworkInstanceBindingExpression which manages the initialization of code and the interfacing with HasBindingExpressions.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=164980332
diff --git a/java/dagger/internal/codegen/AbstractComponentWriter.java b/java/dagger/internal/codegen/AbstractComponentWriter.java
index b930315..8ba6363 100644
--- a/java/dagger/internal/codegen/AbstractComponentWriter.java
+++ b/java/dagger/internal/codegen/AbstractComponentWriter.java
@@ -595,22 +595,14 @@
     component.addMethods(interfaceMethods);
   }
 
-  // TODO(user): Instead of this method knowing about all BindingExpression types, move this
-  // onto a method on different BindingExpression subtypes.
+  // TODO(user): Move this method onto FieldBasedBindingExpression or subtypes of it.
   @Override
-  public CodeBlock getFieldInitialization(BindingExpression bindingExpression) {
-    // If there is no field, don't initialize it.
-    checkState(bindingExpression.hasFieldSpec());
-
+  public CodeBlock getFieldInitialization(FrameworkInstanceBindingExpression bindingExpression) {
     if (bindingExpression.isProducerFromProvider()) {
       return getRequestFulfillment(
           FrameworkDependency.create(bindingExpression.bindingKey(), PRODUCTION));
     }
 
-    // We don't have to check whether we own the field because this method is called only for
-    // the bindingExpressions map values). That map is only populated for bindings we own, while
-    // getBindingExpression(BindingKey) may return those owned by parents.
-
     switch (bindingExpression.bindingKey().kind()) {
       case CONTRIBUTION:
         return contributionBindingInitialization(bindingExpression);
diff --git a/java/dagger/internal/codegen/BindingExpression.java b/java/dagger/internal/codegen/BindingExpression.java
index d84c86a..0aa1cc9 100644
--- a/java/dagger/internal/codegen/BindingExpression.java
+++ b/java/dagger/internal/codegen/BindingExpression.java
@@ -16,11 +16,9 @@
 
 package dagger.internal.codegen;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static dagger.internal.codegen.AnnotationSpecs.Suppression.RAWTYPES;
 import static dagger.internal.codegen.MemberSelect.staticMemberSelect;
-import static dagger.internal.codegen.TypeNames.DELEGATE_FACTORY;
 import static dagger.internal.codegen.TypeNames.PRODUCER;
 import static javax.lang.model.element.Modifier.PRIVATE;
 
@@ -28,152 +26,35 @@
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
-import dagger.internal.DelegateFactory;
 import java.util.Optional;
 import javax.lang.model.util.Elements;
 
 /** The code expressions to declare, initialize, and/or access a binding in a component. */
-final class BindingExpression extends RequestFulfillment {
-  private final Optional<FieldSpec> fieldSpec;
-  private final RequestFulfillment requestFulfillmentDelegate;
-  private final HasBindingExpressions hasBindingExpressions;
-  private final boolean isProducerFromProvider;
-  private InitializationState fieldInitializationState = InitializationState.UNINITIALIZED;
+abstract class BindingExpression {
+  private final BindingKey bindingKey;
 
-  private BindingExpression(
-      RequestFulfillment requestFulfillmentDelegate,
-      Optional<FieldSpec> fieldSpec,
-      HasBindingExpressions hasBindingExpressions,
-      boolean isProducerFromProvider) {
-    super(requestFulfillmentDelegate.bindingKey());
-    this.requestFulfillmentDelegate = requestFulfillmentDelegate;
-    this.fieldSpec = fieldSpec;
-    this.hasBindingExpressions = hasBindingExpressions;
-    this.isProducerFromProvider = isProducerFromProvider;
+  BindingExpression(BindingKey bindingKey) {
+    this.bindingKey = checkNotNull(bindingKey);
   }
 
-  @Override
-  CodeBlock getSnippetForDependencyRequest(DependencyRequest request, ClassName requestingClass) {
-    // TODO(user): We don't always have to initialize ourselves depending on the request and
-    // inlining.
-    maybeInitializeField();
-    return requestFulfillmentDelegate.getSnippetForDependencyRequest(request, requestingClass);
-  }
-
-  @Override
-  CodeBlock getSnippetForFrameworkDependency(
-      FrameworkDependency frameworkDependency, ClassName requestingClass) {
-    maybeInitializeField();
-    return requestFulfillmentDelegate.getSnippetForFrameworkDependency(
-        frameworkDependency, requestingClass);
-  }
-
-  /** Returns {@code true} if this binding expression has a field. */
-  boolean hasFieldSpec() {
-    return fieldSpec.isPresent();
+  /** The key for which this instance can fulfill requests. */
+  final BindingKey bindingKey() {
+    return bindingKey;
   }
 
   /**
-   * Returns the name of the binding's underlying field.
-   *
-   * @throws UnsupportedOperationException if {@link #hasFieldSpec()} is {@code false}
+   * Returns the {@link CodeBlock} that implements the operation represented by the {@link
+   * DependencyRequest request} from the {@code requestingClass}.
    */
-  private String fieldName() {
-    checkHasField();
-    return fieldSpec.get().name;
-  }
-
-  /** Returns true if this binding expression represents a producer from provider. */
-  // TODO(user): remove this and represent this via a subtype of BindingExpression
-  boolean isProducerFromProvider() {
-    return isProducerFromProvider;
-  }
+  abstract CodeBlock getSnippetForDependencyRequest(
+      DependencyRequest request, ClassName requestingClass);
 
   /**
-   * Sets the initialization state for the binding's underlying field. Only valid for field types.
-   *
-   * @throws UnsupportedOperationException if {@link #hasFieldSpec()} is {@code false}
+   * Returns the {@link CodeBlock} that references the {@link FrameworkDependency} as accessed from
+   * the {@code requestingClass}.
    */
-  private void setFieldInitializationState(InitializationState fieldInitializationState) {
-    checkHasField();
-    checkArgument(this.fieldInitializationState.compareTo(fieldInitializationState) < 0);
-    this.fieldInitializationState = fieldInitializationState;
-  }
-
-  private void checkHasField() {
-    if (!hasFieldSpec()) {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-  // Adds our field and initialization of our field to the component.
-  private void maybeInitializeField() {
-    if (!hasFieldSpec()) {
-      return;
-    }
-    switch (fieldInitializationState) {
-      case UNINITIALIZED:
-        // Change our state in case we are recursively invoked via initializeBindingExpression
-        setFieldInitializationState(InitializationState.INITIALIZING);
-        CodeBlock.Builder codeBuilder = CodeBlock.builder();
-        CodeBlock initCode =
-            CodeBlock.of(
-                "this.$L = $L;",
-                fieldName(),
-                checkNotNull(hasBindingExpressions.getFieldInitialization(this)));
-
-        if (fieldInitializationState == InitializationState.DELEGATED) {
-          // If we were recursively invoked, set the delegate factory as part of our initialization
-          String delegateFactoryVariable = fieldName() + "Delegate";
-          codeBuilder
-              .add("$1T $2L = ($1T) $3L;", DELEGATE_FACTORY, delegateFactoryVariable, fieldName())
-              .add(initCode)
-              .add("$L.setDelegatedProvider($L);", delegateFactoryVariable, fieldName())
-              .build();
-        } else {
-          codeBuilder.add(initCode);
-        }
-        hasBindingExpressions.addInitialization(codeBuilder.build());
-        hasBindingExpressions.addField(fieldSpec.get());
-
-        setFieldInitializationState(InitializationState.INITIALIZED);
-        break;
-
-      case INITIALIZING:
-        // We were recursively invoked, so create a delegate factory instead
-        hasBindingExpressions.addInitialization(
-            CodeBlock.of("this.$L = new $T();", fieldName(), DELEGATE_FACTORY));
-        setFieldInitializationState(InitializationState.DELEGATED);
-        break;
-
-      case DELEGATED:
-      case INITIALIZED:
-        break;
-      default:
-        throw new AssertionError("Unhandled initialization state: " + fieldInitializationState);
-    }
-  }
-
-  /** Initialization state for a factory field. */
-  enum InitializationState {
-    /** The field is {@code null}. */
-    UNINITIALIZED,
-
-    /**
-     * The field's dependencies are being set up. If the field is needed in this state, use a {@link
-     * DelegateFactory}.
-     */
-    INITIALIZING,
-
-    /**
-     * The field's dependencies are being set up, but the field can be used because it has already
-     * been set to a {@link DelegateFactory}.
-     */
-    DELEGATED,
-
-    /** The field is set to an undelegated factory. */
-    INITIALIZED;
-  }
+  abstract CodeBlock getSnippetForFrameworkDependency(
+      FrameworkDependency frameworkDependency, ClassName requestingClass);
 
   /** Factory for building a {@link BindingExpression}. */
   static final class Factory {
@@ -206,33 +87,26 @@
     BindingExpression forField(ResolvedBindings resolvedBindings) {
       FieldSpec fieldSpec = generateFrameworkField(resolvedBindings, Optional.empty());
       MemberSelect memberSelect = MemberSelect.localField(componentName, fieldSpec.name);
-      return new BindingExpression(
-          createRequestFulfillment(resolvedBindings, memberSelect),
-          Optional.of(fieldSpec),
-          hasBindingExpressions,
-          false);
+      return create(resolvedBindings, Optional.of(fieldSpec), memberSelect);
     }
 
     BindingExpression forProducerFromProviderField(ResolvedBindings resolvedBindings) {
       FieldSpec fieldSpec = generateFrameworkField(resolvedBindings, Optional.of(PRODUCER));
       MemberSelect memberSelect = MemberSelect.localField(componentName, fieldSpec.name);
-      return new BindingExpression(
-          new ProducerFieldRequestFulfillment(resolvedBindings.bindingKey(), memberSelect),
+      return new ProducerBindingExpression(
+          resolvedBindings.bindingKey(),
           Optional.of(fieldSpec),
           hasBindingExpressions,
+          memberSelect,
           true);
     }
 
-    /** Creates a binding expression for a static method call. */
+    /**
+     * Creates a binding expression for a static method call.
+     */
     Optional<BindingExpression> forStaticMethod(ResolvedBindings resolvedBindings) {
-      Optional<MemberSelect> memberSelect = staticMemberSelect(resolvedBindings);
-      return memberSelect.map(
-          value ->
-              new BindingExpression(
-                  createRequestFulfillment(resolvedBindings, value),
-                  Optional.empty(),
-                  hasBindingExpressions,
-                  false));
+      return staticMemberSelect(resolvedBindings)
+          .map(memberSelect -> create(resolvedBindings, Optional.empty(), memberSelect));
     }
 
     /**
@@ -265,54 +139,54 @@
           && !bindingPackage.get().equals(componentName.packageName());
     }
 
-    private RequestFulfillment createRequestFulfillment(
-        ResolvedBindings resolvedBindings, MemberSelect memberSelect) {
+    private BindingExpression create(
+        ResolvedBindings resolvedBindings,
+        Optional<FieldSpec> fieldSpec,
+        MemberSelect memberSelect) {
       BindingKey bindingKey = resolvedBindings.bindingKey();
       switch (resolvedBindings.bindingType()) {
         case MEMBERS_INJECTION:
-          return new MembersInjectorRequestFulfillment(bindingKey, memberSelect);
+          return new MembersInjectorBindingExpression(
+              bindingKey, fieldSpec, hasBindingExpressions, memberSelect);
         case PRODUCTION:
-          return new ProducerFieldRequestFulfillment(bindingKey, memberSelect);
+          return new ProducerBindingExpression(
+              bindingKey, fieldSpec, hasBindingExpressions, memberSelect, false);
         case PROVISION:
           ProvisionBinding provisionBinding =
               (ProvisionBinding) resolvedBindings.contributionBinding();
 
-          ProviderFieldRequestFulfillment providerFieldRequestFulfillment =
-              new ProviderFieldRequestFulfillment(bindingKey, memberSelect);
+          ProviderBindingExpression providerBindingExpression =
+              new ProviderBindingExpression(
+                  bindingKey, fieldSpec, hasBindingExpressions, memberSelect);
 
           switch (provisionBinding.bindingKind()) {
             case SUBCOMPONENT_BUILDER:
-              return new SubcomponentBuilderRequestFulfillment(
-                  bindingKey, providerFieldRequestFulfillment, subcomponentNames.get(bindingKey));
+              return new SubcomponentBuilderBindingExpression(
+                  providerBindingExpression, subcomponentNames.get(bindingKey));
             case SYNTHETIC_MULTIBOUND_SET:
-              return new SetBindingRequestFulfillment(
-                  bindingKey,
+              return new SetBindingExpression(
                   provisionBinding,
                   graph,
                   hasBindingExpressions,
-                  providerFieldRequestFulfillment,
+                  providerBindingExpression,
                   elements);
             case SYNTHETIC_OPTIONAL_BINDING:
-              return new OptionalBindingRequestFulfillment(
-                  bindingKey,
-                  provisionBinding,
-                  providerFieldRequestFulfillment,
-                  hasBindingExpressions);
+              return new OptionalBindingExpression(
+                  provisionBinding, providerBindingExpression, hasBindingExpressions);
             case INJECTION:
             case PROVISION:
               if (!provisionBinding.scope().isPresent()
                   && !provisionBinding.requiresModuleInstance()
                   && provisionBinding.bindingElement().isPresent()) {
-                return new SimpleMethodRequestFulfillment(
+                return new SimpleMethodBindingExpression(
                     compilerOptions,
-                    bindingKey,
                     provisionBinding,
-                    providerFieldRequestFulfillment,
+                    providerBindingExpression,
                     hasBindingExpressions);
               }
               // fall through
             default:
-              return providerFieldRequestFulfillment;
+              return providerBindingExpression;
           }
         default:
           throw new AssertionError();
diff --git a/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
new file mode 100644
index 0000000..2cd0b91
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
@@ -0,0 +1,163 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.Preconditions.checkNotNull;
+import static dagger.internal.codegen.TypeNames.DELEGATE_FACTORY;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import dagger.internal.DelegateFactory;
+import java.util.Optional;
+
+/**
+ * A {@link BindingExpression} that is always satisfied in components by using an instance of a
+ * {@link FrameworkType}.
+ */
+// TODO(user): consider removing this class and making it a strategy that is created by
+// {Provider,Producer,MembersInjector}BindingExpression
+abstract class FrameworkInstanceBindingExpression extends BindingExpression {
+  private final Optional<FieldSpec> fieldSpec;
+  private final HasBindingExpressions hasBindingExpressions;
+  private final MemberSelect memberSelect;
+  private InitializationState fieldInitializationState = InitializationState.UNINITIALIZED;
+
+  protected FrameworkInstanceBindingExpression(
+      BindingKey bindingKey,
+      Optional<FieldSpec> fieldSpec,
+      HasBindingExpressions hasBindingExpressions,
+      MemberSelect memberSelect) {
+    super(bindingKey);
+    this.hasBindingExpressions = hasBindingExpressions;
+    this.memberSelect = memberSelect;
+    this.fieldSpec = fieldSpec;
+  }
+
+  /**
+   * The expression for the framework instance for this binding. If the instance comes from a
+   * component field, it will be {@link HasBindingExpressions#addInitialization(CodeBlock)
+   * initialized} and {@link HasBindingExpressions#addField(FieldSpec) added} to the component the
+   * first time this method is invoked.
+   */
+  final CodeBlock getFrameworkTypeInstance(ClassName requestingClass) {
+    maybeInitializeField();
+    return memberSelect.getExpressionFor(requestingClass);
+  }
+
+  /**
+   * Returns the name of the binding's underlying field.
+   *
+   * @throws UnsupportedOperationException if no field exists
+   */
+  // TODO(ronshapiro): remove this in favor of $N in a CodeBlock
+  private String fieldName() {
+    checkHasField();
+    return fieldSpec.get().name;
+  }
+
+  /** Returns true if this binding expression represents a producer from provider. */
+  // TODO(user): remove this and represent this via a subtype of BindingExpression
+  abstract boolean isProducerFromProvider();
+
+  /**
+   * Sets the initialization state for the binding's underlying field. Only valid for field types.
+   *
+   * @throws UnsupportedOperationException if no field exists
+   */
+  private void setFieldInitializationState(InitializationState fieldInitializationState) {
+    checkHasField();
+    checkArgument(this.fieldInitializationState.compareTo(fieldInitializationState) < 0);
+    this.fieldInitializationState = fieldInitializationState;
+  }
+
+  private void checkHasField() {
+    if (!fieldSpec.isPresent()) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  // Adds our field and initialization of our field to the component.
+  private void maybeInitializeField() {
+    if (!fieldSpec.isPresent()) {
+      return;
+    }
+    switch (fieldInitializationState) {
+      case UNINITIALIZED:
+        // Change our state in case we are recursively invoked via initializeBindingExpression
+        setFieldInitializationState(InitializationState.INITIALIZING);
+        CodeBlock.Builder codeBuilder = CodeBlock.builder();
+        CodeBlock initCode =
+            CodeBlock.of(
+                "this.$L = $L;",
+                fieldName(),
+                checkNotNull(hasBindingExpressions.getFieldInitialization(this)));
+
+        if (fieldInitializationState == InitializationState.DELEGATED) {
+          // If we were recursively invoked, set the delegate factory as part of our initialization
+          String delegateFactoryVariable = fieldName() + "Delegate";
+          codeBuilder
+              .add("$1T $2L = ($1T) $3L;", DELEGATE_FACTORY, delegateFactoryVariable, fieldName())
+              .add(initCode)
+              .add("$L.setDelegatedProvider($L);", delegateFactoryVariable, fieldName())
+              .build();
+        } else {
+          codeBuilder.add(initCode);
+        }
+        hasBindingExpressions.addInitialization(codeBuilder.build());
+        hasBindingExpressions.addField(fieldSpec.get());
+
+        setFieldInitializationState(InitializationState.INITIALIZED);
+        break;
+
+      case INITIALIZING:
+        // We were recursively invoked, so create a delegate factory instead
+        hasBindingExpressions.addInitialization(
+            CodeBlock.of("this.$L = new $T();", fieldName(), DELEGATE_FACTORY));
+        setFieldInitializationState(InitializationState.DELEGATED);
+        break;
+
+      case DELEGATED:
+      case INITIALIZED:
+        break;
+      default:
+        throw new AssertionError("Unhandled initialization state: " + fieldInitializationState);
+    }
+  }
+
+  /** Initialization state for a factory field. */
+  private enum InitializationState {
+    /** The field is {@code null}. */
+    UNINITIALIZED,
+
+    /**
+     * The field's dependencies are being set up. If the field is needed in this state, use a {@link
+     * DelegateFactory}.
+     */
+    INITIALIZING,
+
+    /**
+     * The field's dependencies are being set up, but the field can be used because it has already
+     * been set to a {@link DelegateFactory}.
+     */
+    DELEGATED,
+
+    /** The field is set to an undelegated factory. */
+    INITIALIZED;
+  }
+}
diff --git a/java/dagger/internal/codegen/HasBindingExpressions.java b/java/dagger/internal/codegen/HasBindingExpressions.java
index 49fb9db..b27705f 100644
--- a/java/dagger/internal/codegen/HasBindingExpressions.java
+++ b/java/dagger/internal/codegen/HasBindingExpressions.java
@@ -44,7 +44,7 @@
       DependencyRequest dependencyRequest, ClassName requestingClass);
 
   /** Returns the expression used to initialize a binding expression field. */
-  CodeBlock getFieldInitialization(BindingExpression bindingExpression);
+  CodeBlock getFieldInitialization(FrameworkInstanceBindingExpression bindingExpression);
 
   /** Adds the given field to the component. */
   void addField(FieldSpec fieldSpec);
diff --git a/java/dagger/internal/codegen/MembersInjectorRequestFulfillment.java b/java/dagger/internal/codegen/MembersInjectorBindingExpression.java
similarity index 64%
rename from java/dagger/internal/codegen/MembersInjectorRequestFulfillment.java
rename to java/dagger/internal/codegen/MembersInjectorBindingExpression.java
index 4f9e955..1185193 100644
--- a/java/dagger/internal/codegen/MembersInjectorRequestFulfillment.java
+++ b/java/dagger/internal/codegen/MembersInjectorBindingExpression.java
@@ -17,34 +17,38 @@
 package dagger.internal.codegen;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.BindingKey.Kind.MEMBERS_INJECTION;
 
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
 import dagger.internal.codegen.DependencyRequest.Kind;
+import java.util.Optional;
 
-/** Fulfills requests for {@link MembersInjectionBinding} instances. */
-final class MembersInjectorRequestFulfillment extends RequestFulfillment {
-  private final MemberSelect membersInjectorFieldSelect;
-
-  MembersInjectorRequestFulfillment(
-      BindingKey bindingKey, MemberSelect membersInjectorFieldSelect) {
-    super(bindingKey);
-    checkArgument(bindingKey.kind().equals(MEMBERS_INJECTION));
-    this.membersInjectorFieldSelect = membersInjectorFieldSelect;
+final class MembersInjectorBindingExpression extends FrameworkInstanceBindingExpression {
+  MembersInjectorBindingExpression(
+      BindingKey bindingKey,
+      Optional<FieldSpec> fieldSpec,
+      HasBindingExpressions hasBindingExpressions,
+      MemberSelect memberSelect) {
+    super(bindingKey, fieldSpec, hasBindingExpressions, memberSelect);
   }
 
   @Override
   public CodeBlock getSnippetForDependencyRequest(
       DependencyRequest request, ClassName requestingClass) {
     checkArgument(request.kind().equals(Kind.MEMBERS_INJECTOR));
-    return membersInjectorFieldSelect.getExpressionFor(requestingClass);
+    return getFrameworkTypeInstance(requestingClass);
   }
 
   @Override
   CodeBlock getSnippetForFrameworkDependency(
       FrameworkDependency frameworkDependency, ClassName requestingClass) {
     checkArgument(frameworkDependency.bindingType().equals(BindingType.MEMBERS_INJECTION));
-    return membersInjectorFieldSelect.getExpressionFor(requestingClass);
+    return getFrameworkTypeInstance(requestingClass);
+  }
+
+  @Override
+  boolean isProducerFromProvider() {
+    return false;
   }
 }
diff --git a/java/dagger/internal/codegen/OptionalBindingRequestFulfillment.java b/java/dagger/internal/codegen/OptionalBindingExpression.java
similarity index 87%
rename from java/dagger/internal/codegen/OptionalBindingRequestFulfillment.java
rename to java/dagger/internal/codegen/OptionalBindingExpression.java
index ed64787..822e0af 100644
--- a/java/dagger/internal/codegen/OptionalBindingRequestFulfillment.java
+++ b/java/dagger/internal/codegen/OptionalBindingExpression.java
@@ -24,19 +24,18 @@
 import dagger.internal.codegen.OptionalType.OptionalKind;
 
 /**
- * A {@link RequestFulfillment} for {@link
- * dagger.internal.codegen.ContributionBinding.Kind#SYNTHETIC_OPTIONAL_BINDING}
+ * A {@link BindingExpression} for {@link
+ * ContributionBinding.Kind#SYNTHETIC_OPTIONAL_BINDING}
  */
-final class OptionalBindingRequestFulfillment extends SimpleInvocationRequestFulfillment {
+final class OptionalBindingExpression extends SimpleInvocationBindingExpression {
   private final ProvisionBinding binding;
   private final HasBindingExpressions hasBindingExpressions;
 
-  OptionalBindingRequestFulfillment(
-      BindingKey bindingKey,
+  OptionalBindingExpression(
       ProvisionBinding binding,
-      RequestFulfillment delegate,
+      BindingExpression delegate,
       HasBindingExpressions hasBindingExpressions) {
-    super(bindingKey, delegate);
+    super(delegate);
     this.binding = binding;
     this.hasBindingExpressions = hasBindingExpressions;
   }
diff --git a/java/dagger/internal/codegen/ProducerBindingExpression.java b/java/dagger/internal/codegen/ProducerBindingExpression.java
new file mode 100644
index 0000000..a39365d
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducerBindingExpression.java
@@ -0,0 +1,60 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.BindingType.PRODUCTION;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import java.util.Optional;
+
+final class ProducerBindingExpression extends FrameworkInstanceBindingExpression {
+  private final boolean isProducerFromProvider;
+
+  ProducerBindingExpression(
+      BindingKey bindingKey,
+      Optional<FieldSpec> fieldSpec,
+      HasBindingExpressions hasBindingExpressions,
+      MemberSelect memberSelect,
+      boolean isProducerFromProvider) {
+    super(bindingKey, fieldSpec, hasBindingExpressions, memberSelect);
+    this.isProducerFromProvider = isProducerFromProvider;
+  }
+
+  @Override
+  CodeBlock getSnippetForDependencyRequest(
+      DependencyRequest request, ClassName requestingClass) {
+    return FrameworkType.PRODUCER.to(request.kind(), getFrameworkTypeInstance(requestingClass));
+  }
+
+  @Override
+  CodeBlock getSnippetForFrameworkDependency(
+      FrameworkDependency frameworkDependency, ClassName requestingClass) {
+    checkArgument(
+        frameworkDependency.bindingType().equals(PRODUCTION),
+        "%s is not a production dependency",
+        frameworkDependency);
+    return getFrameworkTypeInstance(requestingClass);
+  }
+
+  @Override
+  boolean isProducerFromProvider() {
+    return isProducerFromProvider;
+  }
+}
diff --git a/java/dagger/internal/codegen/ProducerFieldRequestFulfillment.java b/java/dagger/internal/codegen/ProducerFieldRequestFulfillment.java
deleted file mode 100644
index a0c61c8..0000000
--- a/java/dagger/internal/codegen/ProducerFieldRequestFulfillment.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 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.internal.codegen;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.BindingKey.Kind.CONTRIBUTION;
-import static dagger.internal.codegen.BindingType.PRODUCTION;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-
-/** Fulfills requests for {@link ProductionBinding} instances. */
-final class ProducerFieldRequestFulfillment extends RequestFulfillment {
-  private final MemberSelect producerFieldSelect;
-
-  ProducerFieldRequestFulfillment(BindingKey bindingKey, MemberSelect producerFieldSelect) {
-    super(bindingKey);
-    checkArgument(bindingKey.kind().equals(CONTRIBUTION));
-    this.producerFieldSelect = producerFieldSelect;
-  }
-
-  @Override
-  public CodeBlock getSnippetForDependencyRequest(
-      DependencyRequest request, ClassName requestingClass) {
-    return FrameworkType.PRODUCER.to(
-        request.kind(), producerFieldSelect.getExpressionFor(requestingClass));
-  }
-
-  @Override
-  CodeBlock getSnippetForFrameworkDependency(
-      FrameworkDependency frameworkDependency, ClassName requestingClass) {
-    checkArgument(
-        frameworkDependency.bindingType().equals(PRODUCTION),
-        "%s is not a production dependency",
-        frameworkDependency);
-    return producerFieldSelect.getExpressionFor(requestingClass);
-  }
-}
diff --git a/java/dagger/internal/codegen/ProviderBindingExpression.java b/java/dagger/internal/codegen/ProviderBindingExpression.java
new file mode 100644
index 0000000..accd391
--- /dev/null
+++ b/java/dagger/internal/codegen/ProviderBindingExpression.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.internal.codegen;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import dagger.producers.internal.Producers;
+import java.util.Optional;
+
+final class ProviderBindingExpression extends FrameworkInstanceBindingExpression {
+  ProviderBindingExpression(
+      BindingKey bindingKey,
+      Optional<FieldSpec> fieldSpec,
+      HasBindingExpressions hasBindingExpressions,
+      MemberSelect memberSelect) {
+    super(bindingKey, fieldSpec, hasBindingExpressions, memberSelect);
+  }
+
+  @Override
+  CodeBlock getSnippetForDependencyRequest(DependencyRequest request, ClassName requestingClass) {
+    return FrameworkType.PROVIDER.to(request.kind(), getFrameworkTypeInstance(requestingClass));
+  }
+
+  @Override
+  CodeBlock getSnippetForFrameworkDependency(
+      FrameworkDependency frameworkDependency, ClassName requestingClass) {
+    switch (frameworkDependency.bindingType()) {
+      case PROVISION:
+        return getFrameworkTypeInstance(requestingClass);
+      case MEMBERS_INJECTION:
+        throw new IllegalArgumentException();
+      case PRODUCTION:
+        return CodeBlock.of(
+            "$T.producerFromProvider($L)",
+            Producers.class,
+            getFrameworkTypeInstance(requestingClass));
+      default:
+        throw new AssertionError();
+    }
+  }
+
+  @Override
+  boolean isProducerFromProvider() {
+    return false;
+  }
+}
diff --git a/java/dagger/internal/codegen/ProviderFieldRequestFulfillment.java b/java/dagger/internal/codegen/ProviderFieldRequestFulfillment.java
deleted file mode 100644
index d17c2e5..0000000
--- a/java/dagger/internal/codegen/ProviderFieldRequestFulfillment.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 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.internal.codegen;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.BindingKey.Kind.CONTRIBUTION;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.producers.internal.Producers;
-
-/** Fulfills requests for {@link ProvisionBinding} instances. */
-final class ProviderFieldRequestFulfillment extends RequestFulfillment {
-  private final MemberSelect providerFieldSelect;
-
-  ProviderFieldRequestFulfillment(BindingKey bindingKey, MemberSelect frameworkFieldSelect) {
-    super(bindingKey);
-    checkArgument(bindingKey.kind().equals(CONTRIBUTION));
-    this.providerFieldSelect = frameworkFieldSelect;
-  }
-
-  @Override
-  public CodeBlock getSnippetForDependencyRequest(
-      DependencyRequest request, ClassName requestingClass) {
-    return FrameworkType.PROVIDER.to(
-        request.kind(), providerFieldSelect.getExpressionFor(requestingClass));
-  }
-
-  @Override
-  CodeBlock getSnippetForFrameworkDependency(
-      FrameworkDependency frameworkDependency, ClassName requestingClass) {
-    switch (frameworkDependency.bindingType()) {
-      case PROVISION:
-        return providerFieldSelect.getExpressionFor(requestingClass);
-      case MEMBERS_INJECTION:
-        throw new IllegalArgumentException();
-      case PRODUCTION:
-        return CodeBlock.of(
-            "$T.producerFromProvider($L)",
-            Producers.class,
-            providerFieldSelect.getExpressionFor(requestingClass));
-      default:
-        throw new AssertionError();
-    }
-  }
-}
diff --git a/java/dagger/internal/codegen/RequestFulfillment.java b/java/dagger/internal/codegen/RequestFulfillment.java
deleted file mode 100644
index db296c0..0000000
--- a/java/dagger/internal/codegen/RequestFulfillment.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2016 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.internal.codegen;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-
-/**
- * A strategy interface for generating a {@link CodeBlock} that represents how a {@link Binding} is
- * used to satisfy a given {@link DependencyRequest}.
- */
-abstract class RequestFulfillment {
-  private final BindingKey bindingKey;
-
-  RequestFulfillment(BindingKey bindingKey) {
-    this.bindingKey = checkNotNull(bindingKey);
-  }
-
-  /** The key for which this instance can fulfill requests. */
-  final BindingKey bindingKey() {
-    return bindingKey;
-  }
-
-  /**
-   * Returns the {@link CodeBlock} that implements the operation represented by the {@link
-   * DependencyRequest request} from the {@code requestingClass}.
-   */
-  abstract CodeBlock getSnippetForDependencyRequest(
-      DependencyRequest request, ClassName requestingClass);
-
-  /**
-   * Returns the {@link CodeBlock} that references the {@link FrameworkDependency} as accessed from
-   * the {@code requestingClass}.
-   */
-  abstract CodeBlock getSnippetForFrameworkDependency(
-      FrameworkDependency frameworkDependency, ClassName requestingClass);
-}
diff --git a/java/dagger/internal/codegen/SetBindingRequestFulfillment.java b/java/dagger/internal/codegen/SetBindingExpression.java
similarity index 94%
rename from java/dagger/internal/codegen/SetBindingRequestFulfillment.java
rename to java/dagger/internal/codegen/SetBindingExpression.java
index 502a15b..d0ca015 100644
--- a/java/dagger/internal/codegen/SetBindingRequestFulfillment.java
+++ b/java/dagger/internal/codegen/SetBindingExpression.java
@@ -32,23 +32,22 @@
 import javax.lang.model.util.Elements;
 
 /**
- * A {@link RequestFulfillment} for {@link
- * dagger.internal.codegen.ContributionBinding.Kind#SYNTHETIC_MULTIBOUND_SET}
+ * A {@link BindingExpression} for {@link
+ * ContributionBinding.Kind#SYNTHETIC_MULTIBOUND_SET}
  */
-final class SetBindingRequestFulfillment extends SimpleInvocationRequestFulfillment {
+final class SetBindingExpression extends SimpleInvocationBindingExpression {
   private final ProvisionBinding binding;
   private final BindingGraph graph;
   private final HasBindingExpressions hasBindingExpressions;
   private final Elements elements;
 
-  SetBindingRequestFulfillment(
-      BindingKey bindingKey,
+  SetBindingExpression(
       ProvisionBinding binding,
       BindingGraph graph,
       HasBindingExpressions hasBindingExpressions,
-      RequestFulfillment delegate,
+      BindingExpression delegate,
       Elements elements) {
-    super(bindingKey, delegate);
+    super(delegate);
     this.binding = binding;
     this.graph = graph;
     this.hasBindingExpressions = hasBindingExpressions;
diff --git a/java/dagger/internal/codegen/SimpleInvocationRequestFulfillment.java b/java/dagger/internal/codegen/SimpleInvocationBindingExpression.java
similarity index 86%
rename from java/dagger/internal/codegen/SimpleInvocationRequestFulfillment.java
rename to java/dagger/internal/codegen/SimpleInvocationBindingExpression.java
index 94e19bd..644b430 100644
--- a/java/dagger/internal/codegen/SimpleInvocationRequestFulfillment.java
+++ b/java/dagger/internal/codegen/SimpleInvocationBindingExpression.java
@@ -21,14 +21,14 @@
 import com.squareup.javapoet.CodeBlock;
 
 /**
- * A {@link RequestFulfillment} that can fulfill its request with a simple call when possible, and
+ * A {@link BindingExpression} that can fulfill its request with a simple call when possible, and
  * otherwise delegates to a backing provider field.
  */
-abstract class SimpleInvocationRequestFulfillment extends RequestFulfillment {
-  private final RequestFulfillment delegate;
+abstract class SimpleInvocationBindingExpression extends BindingExpression {
+  private final BindingExpression delegate;
 
-  SimpleInvocationRequestFulfillment(BindingKey bindingKey, RequestFulfillment delegate) {
-    super(bindingKey);
+  SimpleInvocationBindingExpression(BindingExpression delegate) {
+    super(delegate.bindingKey());
     this.delegate = delegate;
   }
 
diff --git a/java/dagger/internal/codegen/SimpleMethodRequestFulfillment.java b/java/dagger/internal/codegen/SimpleMethodBindingExpression.java
similarity index 95%
rename from java/dagger/internal/codegen/SimpleMethodRequestFulfillment.java
rename to java/dagger/internal/codegen/SimpleMethodBindingExpression.java
index 4844d61..c53a916 100644
--- a/java/dagger/internal/codegen/SimpleMethodRequestFulfillment.java
+++ b/java/dagger/internal/codegen/SimpleMethodBindingExpression.java
@@ -40,18 +40,17 @@
  * requests whenever possible. In cases where direct invocation is not possible, this implementation
  * delegates to one that uses a {@link javax.inject.Provider}.
  */
-final class SimpleMethodRequestFulfillment extends SimpleInvocationRequestFulfillment {
+final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpression {
   private final CompilerOptions compilerOptions;
   private final ProvisionBinding provisionBinding;
   private final HasBindingExpressions hasBindingExpressions;
 
-  SimpleMethodRequestFulfillment(
+  SimpleMethodBindingExpression(
       CompilerOptions compilerOptions,
-      BindingKey bindingKey,
       ProvisionBinding provisionBinding,
-      RequestFulfillment providerDelegate,
+      BindingExpression delegate,
       HasBindingExpressions hasBindingExpressions) {
-    super(bindingKey, providerDelegate);
+    super(delegate);
     this.compilerOptions = compilerOptions;
     checkArgument(
         provisionBinding.implicitDependencies().isEmpty(),
diff --git a/java/dagger/internal/codegen/SubcomponentBuilderRequestFulfillment.java b/java/dagger/internal/codegen/SubcomponentBuilderBindingExpression.java
similarity index 79%
rename from java/dagger/internal/codegen/SubcomponentBuilderRequestFulfillment.java
rename to java/dagger/internal/codegen/SubcomponentBuilderBindingExpression.java
index 6afb95a..0fa5195 100644
--- a/java/dagger/internal/codegen/SubcomponentBuilderRequestFulfillment.java
+++ b/java/dagger/internal/codegen/SubcomponentBuilderBindingExpression.java
@@ -19,12 +19,11 @@
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 
-final class SubcomponentBuilderRequestFulfillment extends SimpleInvocationRequestFulfillment {
+final class SubcomponentBuilderBindingExpression extends SimpleInvocationBindingExpression {
   private final String subcomponentBuilderName;
 
-  SubcomponentBuilderRequestFulfillment(
-      BindingKey bindingKey, RequestFulfillment delegate, String subcomponentBuilderName) {
-    super(bindingKey, delegate);
+  SubcomponentBuilderBindingExpression(BindingExpression delegate, String subcomponentBuilderName) {
+    super(delegate);
     this.subcomponentBuilderName = subcomponentBuilderName;
   }