Inline assisted binding private method in fast init mode.

RELNOTES=n/a
PiperOrigin-RevId: 409516899
diff --git a/java/dagger/internal/codegen/binding/BindingGraph.java b/java/dagger/internal/codegen/binding/BindingGraph.java
index c9a0ce9..019a3b5 100644
--- a/java/dagger/internal/codegen/binding/BindingGraph.java
+++ b/java/dagger/internal/codegen/binding/BindingGraph.java
@@ -44,7 +44,6 @@
 import dagger.spi.model.BindingGraph.DependencyEdge;
 import dagger.spi.model.BindingGraph.Edge;
 import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.BindingKind;
 import dagger.spi.model.ComponentPath;
 import dagger.spi.model.DaggerTypeElement;
 import dagger.spi.model.DependencyRequest;
@@ -158,7 +157,7 @@
               network().successors(node).stream().sorted(nodeOrder()).collect(toImmutableList()));
     }
 
-    public boolean hasframeworkRequest(Binding binding) {
+    public boolean hasFrameworkRequest(Binding binding) {
       return frameworkTypeBindings.contains(binding);
     }
 
@@ -166,31 +165,6 @@
         ImmutableNetwork<Node, Edge> network, ImmutableSet<dagger.spi.model.Binding> bindings) {
       Set<Binding> frameworkRequestBindings = new HashSet<>();
       for (dagger.spi.model.Binding binding : bindings) {
-        // When a delegator binding received an instance request, it will manually create an
-        // instance request for its delegated binding in direct instance binding representation. It
-        // is possible a provider.get() expression will be returned to satisfy the request for the
-        // delegated binding. In this case, the returned expression should have a type cast, because
-        // the returned expression's type can be Object. The type cast is handled by
-        // DelegateRequestRepresentation. If we change to use framework instance binding
-        // representation to handle the delegate bindings, then we will be missing the type cast.
-        // Because in this case, when requesting an instance for the delegator binding, framework
-        // instance binding representation will manually create a provider request for delegated
-        // binding first, then use DerivedFromFrameworkInstanceRequestRepresentaion to wrap that
-        // provider expression. Then we will still have a provider.get(), but it is generated with
-        // two different request representation, so the type cast step is skipped. As the result, we
-        // can't directly switch the delegation binding to always use the framework instance if a
-        // framework request already exists. So I'm adding an temporary exemption for delegate
-        // binding here to make it still use the old generation logic. We might be able to remove
-        // the exemption when we handle the type cast differently.
-        // TODO(wanyingd): fix the type cast problem and remove the exemption for delegate binding.
-        if (binding.kind().equals(BindingKind.DELEGATE)
-            // In fast init mode, for Assisted injection binding, since we manually create a direct
-            // instance when the request type is a Provider, then there can't really be any
-            // framework requests for the binding.
-            // TODO(wanyingd): inline assisted injection binding expression in assisted factory.
-            || binding.kind().equals(BindingKind.ASSISTED_INJECTION)) {
-          continue;
-        }
         ImmutableList<DependencyEdge> edges =
             network.inEdges(binding).stream()
                 .flatMap(instancesOf(DependencyEdge.class))
diff --git a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
index 81ba316..a83b618 100644
--- a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
@@ -18,10 +18,11 @@
 
 import static com.google.auto.common.MoreElements.asType;
 import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethod;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryParameterSpecs;
+import static dagger.internal.codegen.writing.AssistedInjectionParameters.assistedFactoryParameterSpecs;
 
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
@@ -31,13 +32,14 @@
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.binding.BindingGraph;
 import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.javapoet.Expression;
 import dagger.internal.codegen.langmodel.DaggerElements;
 import dagger.internal.codegen.langmodel.DaggerTypes;
 import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.RequestKind;
+import java.util.Optional;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
@@ -49,18 +51,24 @@
  */
 final class AssistedFactoryRequestRepresentation extends RequestRepresentation {
   private final ProvisionBinding binding;
-  private final ComponentRequestRepresentations componentRequestRepresentations;
+  private final BindingGraph graph;
+  private final SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory;
   private final DaggerElements elements;
   private final DaggerTypes types;
+  private final ComponentImplementation componentImplementation;
 
   @AssistedInject
   AssistedFactoryRequestRepresentation(
       @Assisted ProvisionBinding binding,
-      ComponentRequestRepresentations componentRequestRepresentations,
+      BindingGraph graph,
+      ComponentImplementation componentImplementation,
+      SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory,
       DaggerTypes types,
       DaggerElements elements) {
     this.binding = checkNotNull(binding);
-    this.componentRequestRepresentations = componentRequestRepresentations;
+    this.graph = graph;
+    this.componentImplementation = componentImplementation;
+    this.simpleMethodRequestRepresentationFactory = simpleMethodRequestRepresentationFactory;
     this.elements = elements;
     this.types = types;
   }
@@ -69,18 +77,22 @@
   Expression getDependencyExpression(ClassName requestingClass) {
     // An assisted factory binding should have a single request for an assisted injection type.
     DependencyRequest assistedInjectionRequest = getOnlyElement(binding.provisionDependencies());
+    // Get corresponding assisted injection binding.
+    Optional<Binding> localBinding = graph.localContributionBinding(assistedInjectionRequest.key());
+    checkArgument(
+        localBinding.isPresent(),
+        "assisted factory should have a dependency on an assisted injection binding");
     Expression assistedInjectionExpression =
-        ((AssistedPrivateMethodRequestRepresentation)
-                componentRequestRepresentations.getRequestRepresentation(
-                    BindingRequest.bindingRequest(
-                        assistedInjectionRequest.key(), RequestKind.INSTANCE)))
-            .getAssistedDependencyExpression(requestingClass.peerClass(""));
+        simpleMethodRequestRepresentationFactory
+            .create((ProvisionBinding) localBinding.get())
+            .getDependencyExpression(requestingClass.peerClass(""));
     return Expression.create(
         assistedInjectionExpression.type(),
-        CodeBlock.of("$L", anonymousfactoryImpl(assistedInjectionExpression)));
+        CodeBlock.of("$L", anonymousfactoryImpl(localBinding.get(), assistedInjectionExpression)));
   }
 
-  private TypeSpec anonymousfactoryImpl(Expression assistedInjectionExpression) {
+  private TypeSpec anonymousfactoryImpl(
+      Binding assistedBinding, Expression assistedInjectionExpression) {
     TypeElement factory = asType(binding.bindingElement().get());
     DeclaredType factoryType = asDeclared(binding.key().type().java());
     ExecutableElement factoryMethod = assistedFactoryMethod(factory, elements);
@@ -96,7 +108,12 @@
                     .returns(factoryOverride.returnType)
                     .addAnnotations(factoryOverride.annotations)
                     .addExceptions(factoryOverride.exceptions)
-                    .addParameters(assistedFactoryParameterSpecs(binding, elements, types))
+                    .addParameters(
+                        assistedFactoryParameterSpecs(
+                            binding,
+                            elements,
+                            types,
+                            componentImplementation.shardImplementation(assistedBinding)))
                     .addStatement("return $L", assistedInjectionExpression.codeBlock())
                     .build());
 
diff --git a/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
index 3b39bde..c117628 100644
--- a/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
+++ b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
@@ -20,12 +20,15 @@
 import static com.google.auto.common.MoreTypes.asDeclared;
 import static com.google.auto.common.MoreTypes.asExecutable;
 import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
 
 import com.google.common.collect.ImmutableList;
 import com.squareup.javapoet.ParameterSpec;
 import com.squareup.javapoet.TypeName;
 import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
+import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFactoryMetadata;
 import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.langmodel.DaggerElements;
 import dagger.internal.codegen.langmodel.DaggerTypes;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
 import dagger.spi.model.BindingKind;
@@ -38,6 +41,34 @@
 /** Utility class for generating unique assisted parameter names for a component shard. */
 final class AssistedInjectionParameters {
   /**
+   * Returns the list of assisted factory parameters as {@link ParameterSpec}s.
+   *
+   * <p>The type of each parameter will be the resolved type given by the binding key, and the name
+   * of each parameter will be the name given in the {@link
+   * dagger.assisted.AssistedInject}-annotated constructor.
+   */
+  public static ImmutableList<ParameterSpec> assistedFactoryParameterSpecs(
+      Binding binding,
+      DaggerElements elements,
+      DaggerTypes types,
+      ShardImplementation shardImplementation) {
+    checkArgument(binding.kind() == BindingKind.ASSISTED_FACTORY);
+    AssistedFactoryMetadata metadata =
+        AssistedFactoryMetadata.create(binding.bindingElement().get().asType(), elements, types);
+    ExecutableType factoryMethodType =
+        asExecutable(
+            types.asMemberOf(asDeclared(binding.key().type().java()), metadata.factoryMethod()));
+    return assistedParameterSpecs(
+        // Use the order of the parameters from the @AssistedFactory method but use the parameter
+        // names of the @AssistedInject constructor.
+        metadata.assistedFactoryAssistedParameters().stream()
+            .map(metadata.assistedInjectAssistedParametersMap()::get)
+            .collect(toImmutableList()),
+        factoryMethodType.getParameterTypes(),
+        shardImplementation);
+  }
+
+  /**
    * Returns the list of assisted parameters as {@link ParameterSpec}s.
    *
    * <p>The type of each parameter will be the resolved type given by the binding key, and the name
diff --git a/java/dagger/internal/codegen/writing/AssistedPrivateMethodRequestRepresentation.java b/java/dagger/internal/codegen/writing/AssistedPrivateMethodRequestRepresentation.java
deleted file mode 100644
index aa117db..0000000
--- a/java/dagger/internal/codegen/writing/AssistedPrivateMethodRequestRepresentation.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2021 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameterSpecs;
-import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
-import static dagger.internal.codegen.writing.AssistedInjectionParameters.assistedParameterSpecs;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.PRIVATE_METHOD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeName;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.RequestKind;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression that wraps private method call for assisted fatory creation. */
-final class AssistedPrivateMethodRequestRepresentation extends MethodRequestRepresentation {
-  private final ShardImplementation shardImplementation;
-  private final ContributionBinding binding;
-  private final BindingRequest request;
-  private final RequestRepresentation wrappedRequestRepresentation;
-  private final CompilerOptions compilerOptions;
-  private final DaggerTypes types;
-  private String methodName;
-
-  @AssistedInject
-  AssistedPrivateMethodRequestRepresentation(
-      @Assisted BindingRequest request,
-      @Assisted ContributionBinding binding,
-      @Assisted RequestRepresentation wrappedRequestRepresentation,
-      ComponentImplementation componentImplementation,
-      DaggerTypes types,
-      CompilerOptions compilerOptions) {
-    super(componentImplementation.shardImplementation(binding), types);
-    checkArgument(binding.kind() == BindingKind.ASSISTED_INJECTION);
-    checkArgument(request.requestKind() == RequestKind.INSTANCE);
-    this.binding = checkNotNull(binding);
-    this.request = checkNotNull(request);
-    this.wrappedRequestRepresentation = checkNotNull(wrappedRequestRepresentation);
-    this.shardImplementation = componentImplementation.shardImplementation(binding);
-    this.compilerOptions = compilerOptions;
-    this.types = types;
-  }
-
-  Expression getAssistedDependencyExpression(ClassName requestingClass) {
-    return Expression.create(
-        returnType(),
-        requestingClass.equals(shardImplementation.name())
-            ? CodeBlock.of(
-                "$N($L)", methodName(), parameterNames(assistedParameterSpecs(binding, types)))
-            : CodeBlock.of(
-                "$L.$N($L)",
-                shardImplementation.shardFieldReference(),
-                methodName(),
-                parameterNames(assistedParameterSpecs(binding, types))));
-  }
-
-  @Override
-  protected CodeBlock methodCall() {
-    throw new IllegalStateException("This should not be accessed");
-  }
-
-  @Override
-  protected TypeMirror returnType() {
-    return types.accessibleType(binding.contributedType(), shardImplementation.name());
-  }
-
-  private String methodName() {
-    if (methodName == null) {
-      // Have to set methodName field before implementing the method in order to handle recursion.
-      methodName = shardImplementation.getUniqueMethodName(request);
-
-      // TODO(bcorso): Fix the order that these generated methods are written to the component.
-      shardImplementation.addMethod(
-          PRIVATE_METHOD,
-          methodBuilder(methodName)
-              .addModifiers(PRIVATE)
-              .addParameters(assistedParameterSpecs(binding, types, shardImplementation))
-              .returns(TypeName.get(returnType()))
-              .addStatement(
-                  "return $L",
-                  wrappedRequestRepresentation
-                      .getDependencyExpression(shardImplementation.name())
-                      .codeBlock())
-              .build());
-    }
-    return methodName;
-  }
-
-  @AssistedFactory
-  static interface Factory {
-    AssistedPrivateMethodRequestRepresentation create(
-        BindingRequest request,
-        ContributionBinding binding,
-        RequestRepresentation wrappedRequestRepresentation);
-  }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentImplementation.java b/java/dagger/internal/codegen/writing/ComponentImplementation.java
index af645f4..2f4d2d6 100644
--- a/java/dagger/internal/codegen/writing/ComponentImplementation.java
+++ b/java/dagger/internal/codegen/writing/ComponentImplementation.java
@@ -431,6 +431,7 @@
     private final UniqueNameSet componentFieldNames = new UniqueNameSet();
     private final UniqueNameSet componentMethodNames = new UniqueNameSet();
     private final UniqueNameSet componentClassNames = new UniqueNameSet();
+    private final UniqueNameSet assistedParamNames = new UniqueNameSet();
     private final List<CodeBlock> initializations = new ArrayList<>();
     private final Map<Key, CodeBlock> cancellations = new LinkedHashMap<>();
     private final Map<VariableElement, String> uniqueAssistedName = new LinkedHashMap<>();
@@ -443,6 +444,7 @@
     private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
         MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
     private final List<Supplier<TypeSpec>> typeSuppliers = new ArrayList<>();
+    private boolean initialized = false; // This is used for initializing assistedParamNames.
 
     private ShardImplementation(ClassName name) {
       this.name = name;
@@ -580,11 +582,26 @@
       return componentFieldNames.getUniqueName(name);
     }
 
+    String getUniqueAssistedParamName(String name) {
+      if (!initialized) {
+        // Assisted params will be used in switching provider, so they can't conflict with component
+        // field names in switching provider. {@link UniqueNameSet#getUniqueName} will add the
+        // component field names to the unique set if it does not exists. If the name already exists
+        // in the set, then a dedupe will be performed automatically on the passed in name, and the
+        // newly created unique name will then be added to the set.
+        componentFieldsByImplementation()
+            .values()
+            .forEach(fieldSpec -> assistedParamNames.getUniqueName(fieldSpec.name));
+        initialized = true;
+      }
+      return assistedParamNames.getUniqueName(name);
+    }
+
     public String getUniqueFieldNameForAssistedParam(VariableElement element) {
       if (uniqueAssistedName.containsKey(element)) {
         return uniqueAssistedName.get(element);
       }
-      String name = getUniqueFieldName(element.getSimpleName().toString());
+      String name = getUniqueAssistedParamName(element.getSimpleName().toString());
       uniqueAssistedName.put(element, name);
       return name;
     }
diff --git a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
index b899768..c90d813 100644
--- a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
@@ -27,7 +27,6 @@
 import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
 import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.BindingKind;
 import dagger.spi.model.RequestKind;
 import java.util.HashMap;
 import java.util.Map;
@@ -44,8 +43,6 @@
       immediateFutureRequestRepresentationFactory;
   private final PrivateMethodRequestRepresentation.Factory
       privateMethodRequestRepresentationFactory;
-  private final AssistedPrivateMethodRequestRepresentation.Factory
-      assistedPrivateMethodRequestRepresentationFactory;
   private final UnscopedDirectInstanceRequestRepresentationFactory
       unscopedDirectInstanceRequestRepresentationFactory;
   private final Map<BindingRequest, RequestRepresentation> requestRepresentations = new HashMap<>();
@@ -58,8 +55,6 @@
       ComponentMethodRequestRepresentation.Factory componentMethodRequestRepresentationFactory,
       ImmediateFutureRequestRepresentation.Factory immediateFutureRequestRepresentationFactory,
       PrivateMethodRequestRepresentation.Factory privateMethodRequestRepresentationFactory,
-      AssistedPrivateMethodRequestRepresentation.Factory
-          assistedPrivateMethodRequestRepresentationFactory,
       UnscopedDirectInstanceRequestRepresentationFactory
           unscopedDirectInstanceRequestRepresentationFactory) {
     this.binding = binding;
@@ -70,8 +65,6 @@
     this.privateMethodRequestRepresentationFactory = privateMethodRequestRepresentationFactory;
     this.unscopedDirectInstanceRequestRepresentationFactory =
         unscopedDirectInstanceRequestRepresentationFactory;
-    this.assistedPrivateMethodRequestRepresentationFactory =
-        assistedPrivateMethodRequestRepresentationFactory;
   }
 
   public RequestRepresentation getRequestRepresentation(BindingRequest request) {
@@ -82,7 +75,9 @@
   private RequestRepresentation getRequestRepresentationUncached(BindingRequest request) {
     switch (request.requestKind()) {
       case INSTANCE:
-        return instanceRequestRepresentation();
+        return requiresMethodEncapsulation(binding)
+            ? wrapInMethod(unscopedDirectInstanceRequestRepresentationFactory.create(binding))
+            : unscopedDirectInstanceRequestRepresentationFactory.create(binding);
 
       case FUTURE:
         return immediateFutureRequestRepresentationFactory.create(
@@ -95,19 +90,6 @@
     }
   }
 
-  private RequestRepresentation instanceRequestRepresentation() {
-    RequestRepresentation directInstanceExpression =
-        unscopedDirectInstanceRequestRepresentationFactory.create(binding);
-    if (binding.kind() == BindingKind.ASSISTED_INJECTION) {
-      BindingRequest request = bindingRequest(binding.key(), RequestKind.INSTANCE);
-      return assistedPrivateMethodRequestRepresentationFactory.create(
-          request, binding, directInstanceExpression);
-    }
-    return requiresMethodEncapsulation(binding)
-        ? wrapInMethod(RequestKind.INSTANCE, directInstanceExpression)
-        : directInstanceExpression;
-  }
-
   /**
    * Returns a binding expression that uses a given one as the body of a method that users call. If
    * a component provision method matches it, it will be the method implemented. If it does not
@@ -115,14 +97,13 @@
    * binding method will be written. If the binding doesn't match a component method and is not
    * modifiable, then a new private method will be written.
    */
-  RequestRepresentation wrapInMethod(
-      RequestKind requestKind, RequestRepresentation bindingExpression) {
+  RequestRepresentation wrapInMethod(RequestRepresentation bindingExpression) {
     // If we've already wrapped the expression, then use the delegate.
     if (bindingExpression instanceof MethodRequestRepresentation) {
       return bindingExpression;
     }
 
-    BindingRequest request = bindingRequest(binding.key(), requestKind);
+    BindingRequest request = bindingRequest(binding.key(), RequestKind.INSTANCE);
     Optional<ComponentMethodDescriptor> matchingComponentMethod =
         graph.componentDescriptor().firstMatchingComponentMethod(request);
 
diff --git a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
index 22970ab..1e87838 100644
--- a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
@@ -29,6 +29,7 @@
 import dagger.internal.codegen.binding.ProvisionBinding;
 import dagger.internal.codegen.compileroption.CompilerOptions;
 import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.spi.model.BindingKind;
 import dagger.spi.model.RequestKind;
 
 /**
@@ -90,7 +91,31 @@
     // form a loop. There are also difficulties introduced by manually created framework requests.
     // TODO(wanyingd): refactor framework instance so that we don't need to generate both direct
     // instance and framework instance representation for the same binding.
-    if (isFastInit && graph.topLevelBindingGraph().hasframeworkRequest(binding)) {
+    if (isFastInit
+        && graph.topLevelBindingGraph().hasFrameworkRequest(binding)
+        // When a delegator binding receives an instance request, it will manually create an
+        // instance request for its delegated binding in direct instance binding representation. It
+        // is possible a provider.get() expression will be returned to satisfy the request for the
+        // delegated binding. In this case, the returned expression should have a type cast, because
+        // the returned expression's type can be Object. The type cast is handled by
+        // DelegateRequestRepresentation.
+        //
+        // If framework instance binding representation is used to handle the delegate bindings
+        // instead of direct instance, then the type cast will be skipped.
+        //
+        // Because in this case, when requesting an instance for the delegator binding, framework
+        // instance binding representation will manually create a provider request for delegated
+        // binding first, then use DerivedFromFrameworkInstanceRequestRepresentaion to wrap that
+        // provider expression. Eventually, the returned expression will still be a provider.get(),
+        // but it is generated with two different request representations, so the type cast step is
+        // skipped, and a type cast error will be thrown.
+        //
+        // That's why a temporary exemption for delegate binding is needed to make it still use the
+        // old generation logic. The exemption might be removable if the code is changed to handle
+        // the type case differently.
+        // TODO(b/206111117): fix the type cast problem and remove the exemption for delegate
+        // binding.
+        && !binding.kind().equals(BindingKind.DELEGATE)) {
       return false;
     }
 
@@ -100,15 +125,13 @@
         // InstanceFactory.create(Foo_MembersInjector.create(...)).
         // TODO(b/199889259): Consider optimizing this for fastInit mode.
       case ASSISTED_FACTORY:
-        return false;
         // Assisted factory binding can be requested with framework request, and it is essentially a
         // provider for assisted injection binding. So we will always return framework instance for
         // assisted factory bindings.
+        return false;
       case ASSISTED_INJECTION:
-        // We still return direct instance for assisted injection binding in fast init mode, because
-        // we want to avoid requiring dependencies as providers in fast init for now. This might
-        // change after we merge fast init mode and default mode.
-        return isFastInit;
+        throw new IllegalStateException(
+            "Assisted injection binding shouldn't be requested with an instance request.");
       default:
         // We don't need to use Provider#get() if there's no caching, so use a direct instance.
         // TODO(bcorso): This can be optimized in cases where we know a Provider field already
diff --git a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
index c58e3d1..6437774 100644
--- a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
+++ b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
@@ -115,11 +115,11 @@
       case ASSISTED_FACTORY:
         return assistedFactoryRequestRepresentationFactory.create((ProvisionBinding) binding);
 
-      case ASSISTED_INJECTION:
       case INJECTION:
       case PROVISION:
         return simpleMethodRequestRepresentationFactory.create((ProvisionBinding) binding);
 
+      case ASSISTED_INJECTION:
       case MEMBERS_INJECTOR:
       case MEMBERS_INJECTION:
       case COMPONENT_PRODUCTION:
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java b/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java
new file mode 100644
index 0000000..af9b40e
--- /dev/null
+++ b/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 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.functional.assisted;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.BindsInstance;
+import dagger.Component;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AssistedFactoryDuplicatedParamNamesTest {
+  static final class Foo {
+    private final String arg;
+    private final Bar bar;
+
+    @AssistedInject
+    Foo(@Assisted String arg, Bar bar) {
+      this.arg = arg;
+      this.bar = bar;
+    }
+
+    Bar getBar() {
+      return bar;
+    }
+
+    String getArg() {
+      return arg;
+    }
+  }
+
+  static final class Bar {}
+
+  @AssistedFactory
+  interface FooFactory {
+    Foo create(String arg);
+  }
+
+  @Component
+  interface TestComponent {
+    @Component.Factory
+    interface Factory {
+      TestComponent create(@BindsInstance Bar arg);
+    }
+
+    FooFactory fooFactory();
+  }
+
+  @Test
+  public void duplicatedParameterNames_doesNotConflict() {
+    String str = "test";
+    Bar bar = new Bar();
+
+    Foo foo =
+        DaggerAssistedFactoryDuplicatedParamNamesTest_TestComponent.factory()
+            .create(bar)
+            .fooFactory()
+            .create(str);
+
+    assertThat(foo.getArg()).isEqualTo(str);
+    assertThat(foo.getBar()).isEqualTo(bar);
+  }
+}
diff --git a/javatests/dagger/internal/codegen/AssistedFactoryTest.java b/javatests/dagger/internal/codegen/AssistedFactoryTest.java
index a78c051..565e1cd 100644
--- a/javatests/dagger/internal/codegen/AssistedFactoryTest.java
+++ b/javatests/dagger/internal/codegen/AssistedFactoryTest.java
@@ -102,10 +102,6 @@
                 "  private final DaggerTestComponent testComponent = this;",
                 "  private Provider<FooFactory> fooFactoryProvider;",
                 "",
-                "  private Foo foo(String str) {",
-                "    return new Foo(str, new Bar());",
-                "  }",
-                "",
                 "  @SuppressWarnings(\"unchecked\")",
                 "  private void initialize() {",
                 "    this.fooFactoryProvider = SingleCheck.provider(new"
@@ -129,7 +125,7 @@
                 "        return (T) new FooFactory() {",
                 "          @Override",
                 "          public Foo create(String str) {",
-                "            return testComponent.foo(str);",
+                "            return new Foo(str, new Bar());",
                 "          }",
                 "        };",
                 "",
@@ -226,10 +222,6 @@
                 "    return new Bar(fooFactoryProvider.get());",
                 "  }",
                 "",
-                "  private Foo foo(String str) {",
-                "    return new Foo(str, bar());",
-                "  }",
-                "",
                 "  @SuppressWarnings(\"unchecked\")",
                 "  private void initialize() {",
                 "    this.fooFactoryProvider = SingleCheck.provider(new"
@@ -253,7 +245,7 @@
                 "        return (T) new FooFactory() {",
                 "          @Override",
                 "          public Foo create(String str) {",
-                "            return testComponent.foo(str);",
+                "            return new Foo(str, testComponent.bar())",
                 "          }",
                 "        };",
                 "",
@@ -293,24 +285,21 @@
   }
 
   @Test
-  public void testInjectParamDuplicateNames() {
-    JavaFileObject componentSrc =
+  public void assistedParamConflictsWithComponentFieldName_successfulyDeduped() {
+    JavaFileObject foo =
         JavaFileObjects.forSourceLines(
-            "test.TestComponent",
+            "test.Foo",
             "package test;",
             "",
-            "import dagger.BindsInstance;",
-            "import dagger.Component;",
+            "import dagger.assisted.Assisted;",
+            "import dagger.assisted.AssistedInject;",
+            "import javax.inject.Provider;",
             "",
-            "@Component",
-            "interface TestComponent {",
-            "  @Component.Factory",
-            "  interface Factory {",
-            "    TestComponent create(@BindsInstance Bar arg);",
-            "  }",
-            "  FooFactory getFooFactory();",
+            "class Foo {",
+            "  @AssistedInject",
+            "  Foo(@Assisted String testComponent, Provider<Bar> bar) {}",
             "}");
-    JavaFileObject factorySrc =
+    JavaFileObject fooFactory =
         JavaFileObjects.forSourceLines(
             "test.FooFactory",
             "package test;",
@@ -318,51 +307,49 @@
             "import dagger.assisted.AssistedFactory;",
             "",
             "@AssistedFactory",
-            "public interface FooFactory {",
-            "  Foo create(Integer arg);",
+            "interface FooFactory {",
+            "  Foo create(String factoryStr);",
             "}");
-    JavaFileObject barSrc =
-        JavaFileObjects.forSourceLines("test.Bar", "package test;", "", "interface Bar {}");
-    JavaFileObject injectSrc =
+    JavaFileObject bar =
         JavaFileObjects.forSourceLines(
-            "test.Foo",
+            "test.Bar",
             "package test;",
             "",
-            "import dagger.assisted.Assisted;",
-            "import dagger.assisted.AssistedInject;",
+            "import javax.inject.Inject;",
             "",
-            "class Foo {",
-            "  @AssistedInject",
-            "  Foo(Bar bar, @Assisted Integer arg) {}",
+            "class Bar {",
+            "  @Inject Bar() {}",
             "}");
-    JavaFileObject generatedSrc =
+    JavaFileObject component =
+        JavaFileObjects.forSourceLines(
+            "test.TestComponent",
+            "package test;",
+            "",
+            "import dagger.Component;",
+            "",
+            "@Component",
+            "interface TestComponent {",
+            "  FooFactory fooFactory();",
+            "}");
+    JavaFileObject generatedComponent =
         compilerMode
             .javaFileBuilder("test.DaggerTestComponent")
             .addLines("package test;", "", GeneratedLines.generatedAnnotations())
             .addLinesIn(
                 FAST_INIT_MODE,
                 "final class DaggerTestComponent implements TestComponent {",
-                "  private final Bar arg2;",
                 "  private final DaggerTestComponent testComponent = this;",
                 "  private Provider<FooFactory> fooFactoryProvider;",
                 "",
-                "  private DaggerTestComponent(Bar argParam) {",
-                "    this.arg2 = argParam;",
-                "    initialize(argParam);",
-                "  }",
-                "",
-                "  private Foo foo(Integer arg) {",
-                "    return new Foo(arg2, arg);",
-                "  }",
-                "",
                 "  @SuppressWarnings(\"unchecked\")",
-                "  private void initialize(final Bar argParam) {",
-                "    this.fooFactoryProvider = SingleCheck.provider(new"
-                    + " SwitchingProvider<FooFactory>(testComponent, 0));",
+                "  private void initialize() {",
+                "    this.barProvider = new SwitchingProvider<>(testComponent, 1);",
+                "    this.fooFactoryProvider = SingleCheck.provider(",
+                "      new SwitchingProvider<FooFactory>(testComponent, 0));",
                 "  }",
                 "",
                 "  @Override",
-                "  public FooFactory getFooFactory() {",
+                "  public FooFactory fooFactory() {",
                 "    return fooFactoryProvider.get();",
                 "  }",
                 "",
@@ -370,7 +357,6 @@
                 "    private final DaggerTestComponent testComponent;",
                 "    private final int id;",
                 "",
-                "",
                 "    @SuppressWarnings(\"unchecked\")",
                 "    @Override",
                 "    public T get() {",
@@ -378,11 +364,11 @@
                 "        case 0:",
                 "        return (T) new FooFactory() {",
                 "          @Override",
-                "          public Foo create(Integer arg) {",
-                "            return testComponent.foo(arg);",
+                "          public Foo create(String testComponent2) {",
+                "            return new Foo(testComponent2, testComponent.barProvider);",
                 "          }",
                 "        };",
-                "",
+                "        case 1: return (T) new Bar();",
                 "        default: throw new AssertionError(id);",
                 "      }",
                 "    }",
@@ -391,201 +377,31 @@
             .addLinesIn(
                 DEFAULT_MODE,
                 "final class DaggerTestComponent implements TestComponent {",
-                "  private final DaggerTestComponent testComponent = this;",
-                "  private Provider<Bar> argProvider;",
+                "",
                 "  private Foo_Factory fooProvider;",
+                "",
                 "  private Provider<FooFactory> fooFactoryProvider;",
                 "",
-                "  private DaggerTestComponent(Bar argParam) {",
-                "    initialize(argParam);",
-                "  }",
-                "",
-                "  public static TestComponent.Factory factory() {",
-                "    return new Factory();",
-                "  }",
-                "",
                 "  @SuppressWarnings(\"unchecked\")",
-                "  private void initialize(final Bar argParam) {",
-                "    this.argProvider = InstanceFactory.create(argParam);",
-                "    this.fooProvider = Foo_Factory.create(argProvider);",
+                "  private void initialize() {",
+                "    this.fooProvider = Foo_Factory.create(Bar_Factory.create());",
                 "    this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
                 "  }",
                 "",
                 "  @Override",
-                "  public FooFactory getFooFactory() {",
+                "  public FooFactory fooFactory() {",
                 "    return fooFactoryProvider.get();",
                 "  }",
-                "",
-                "  private static final class Factory implements TestComponent.Factory {",
-                "    @Override",
-                "    public TestComponent create(Bar arg) {",
-                "      Preconditions.checkNotNull(arg);",
-                "      return new DaggerTestComponent(arg);",
-                "    }",
-                "  }",
                 "}")
             .build();
-    Compilation compilation =
-        compilerWithOptions(compilerMode.javacopts())
-            .compile(componentSrc, factorySrc, barSrc, injectSrc);
-    assertThat(compilation).succeeded();
-    assertThat(compilation)
-        .generatedSourceFile("test.DaggerTestComponent")
-        .containsElementsIn(generatedSrc);
-  }
 
-  @Test
-  public void testAssistParamDuplicateNames() {
-    JavaFileObject componentSrc =
-        JavaFileObjects.forSourceLines(
-            "test.TestComponent",
-            "package test;",
-            "",
-            "import dagger.BindsInstance;",
-            "import dagger.Component;",
-            "",
-            "@Component",
-            "interface TestComponent {",
-            "  @Component.Factory",
-            "  interface Factory {",
-            "    TestComponent create(@BindsInstance Bar arg);",
-            "  }",
-            "  Bar getBar();",
-            "  FooFactory getFooFactory();",
-            "}");
-    JavaFileObject factorySrc =
-        JavaFileObjects.forSourceLines(
-            "test.FooFactory",
-            "package test;",
-            "",
-            "import dagger.assisted.AssistedFactory;",
-            "",
-            "@AssistedFactory",
-            "public interface FooFactory {",
-            "  Foo create(Integer arg);",
-            "}");
-    JavaFileObject barSrc =
-        JavaFileObjects.forSourceLines("test.Bar", "package test;", "", "interface Bar {}");
-    JavaFileObject injectSrc =
-        JavaFileObjects.forSourceLines(
-            "test.Foo",
-            "package test;",
-            "",
-            "import dagger.assisted.Assisted;",
-            "import dagger.assisted.AssistedInject;",
-            "",
-            "class Foo {",
-            "  @AssistedInject",
-            "  Foo(Bar bar, @Assisted Integer arg) {}",
-            "}");
-    JavaFileObject generatedSrc =
-        compilerMode
-            .javaFileBuilder("test.DaggerTestComponent")
-            .addLines("package test;", "", GeneratedLines.generatedAnnotations())
-            .addLinesIn(
-                FAST_INIT_MODE,
-                "final class DaggerTestComponent implements TestComponent {",
-                "  private final Bar arg;",
-                "  private final DaggerTestComponent testComponent = this;",
-                "  private Provider<FooFactory> fooFactoryProvider;",
-                "",
-                "  private DaggerTestComponent(Bar argParam) {",
-                "    this.arg = argParam;",
-                "    initialize(argParam);",
-                "  }",
-                "",
-                "  private Foo foo(Integer arg2) {",
-                "    return new Foo(arg, arg2);",
-                "  }",
-                "",
-                "  @SuppressWarnings(\"unchecked\")",
-                "  private void initialize(final Bar argParam) {",
-                "    this.fooFactoryProvider = SingleCheck.provider(new"
-                    + " SwitchingProvider<FooFactory>(testComponent, 0));",
-                "  }",
-                "",
-                "  @Override",
-                "  public Bar getBar() {",
-                "    return arg;",
-                "  }",
-                "",
-                "  @Override",
-                "  public FooFactory getFooFactory() {",
-                "    return fooFactoryProvider.get();",
-                "  }",
-                "",
-                "  private static final class SwitchingProvider<T> implements Provider<T> {",
-                "    private final DaggerTestComponent testComponent;",
-                "    private final int id;",
-                "",
-                "    @SuppressWarnings(\"unchecked\")",
-                "    @Override",
-                "    public T get() {",
-                "      switch (id) {",
-                "        case 0:",
-                "        return (T) new FooFactory() {",
-                "          @Override",
-                "          public Foo create(Integer arg) {",
-                "            return testComponent.foo(arg);",
-                "          }",
-                "        };",
-                "",
-                "        default: throw new AssertionError(id);",
-                "      }",
-                "    }",
-                "  }",
-                "}")
-            .addLinesIn(
-                DEFAULT_MODE,
-                "final class DaggerTestComponent implements TestComponent {",
-                "  private final Bar arg;",
-                "  private final DaggerTestComponent testComponent = this;",
-                "  private Provider<Bar> argProvider;",
-                "  private Foo_Factory fooProvider;",
-                "  private Provider<FooFactory> fooFactoryProvider;",
-                "",
-                "  private DaggerTestComponent(Bar argParam) {",
-                "    this.arg = argParam;",
-                "    initialize(argParam);",
-                "  }",
-                "",
-                "  public static TestComponent.Factory factory() {",
-                "    return new Factory();",
-                "  }",
-                "",
-                "  @SuppressWarnings(\"unchecked\")",
-                "  private void initialize(final Bar argParam) {",
-                "    this.argProvider = InstanceFactory.create(argParam);",
-                "    this.fooProvider = Foo_Factory.create(argProvider);",
-                "    this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
-                "  }",
-                "",
-                "  @Override",
-                "  public Bar getBar() {",
-                "    return arg;",
-                "  }",
-                "",
-                "  @Override",
-                "  public FooFactory getFooFactory() {",
-                "    return fooFactoryProvider.get();",
-                "  }",
-                "",
-                "  private static final class Factory implements TestComponent.Factory {",
-                "    @Override",
-                "    public TestComponent create(Bar arg) {",
-                "      Preconditions.checkNotNull(arg);",
-                "      return new DaggerTestComponent(arg);",
-                "    }",
-                "  }",
-                "}")
-            .build();
     Compilation compilation =
-        compilerWithOptions(compilerMode.javacopts())
-            .compile(componentSrc, factorySrc, barSrc, injectSrc);
+        compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, fooFactory, component);
+
     assertThat(compilation).succeeded();
     assertThat(compilation)
         .generatedSourceFile("test.DaggerTestComponent")
-        .containsElementsIn(generatedSrc);
+        .containsElementsIn(generatedComponent);
   }
 
   @Test
@@ -733,10 +549,6 @@
                 "  private final DaggerTestComponent testComponent = this;",
                 "  private Provider<FooFactory<String>> fooFactoryProvider;",
                 "",
-                "  private Foo<String> fooOfString(String arg) {",
-                "    return new Foo<String>(arg);",
-                "  }",
-                "",
                 "  @SuppressWarnings(\"unchecked\")",
                 "  private void initialize() {",
                 "    this.fooFactoryProvider = SingleCheck.provider(new"
@@ -759,7 +571,7 @@
                 "        case 0: return (T) new FooFactory<String>() {",
                 "          @Override",
                 "          public Foo<String> create(String arg) {",
-                "            return testComponent.fooOfString(arg);",
+                "            return new Foo<String>(arg)",
                 "          }",
                 "        };",
                 "",