Simplify binding expression creation logic. Specifically, make it easier to reason about when we use direct expressions vs. wrapping them in methods vs. creating FIBEs. Make it easier to see that all request kinds other than instance and provider are derived from either instance or provider, and that often instance is derived from provider or the other way around.

Derive future requests from instances, and Lazy and Provider<Lazy> requests from providers.

Make the logic for instance requests return either a direct expression, a direct expression wrapped in a method, or an expression that calls get() on the provider.

Make the logic for provider expressions either wrap the instance expression in a method, delegate to the @Binds target, or use a provider instance.

Decide whether to wrap an instance expression in a method first (based on complexity and the need for scoping), and then secondly decide whether to use a component provision method or a private method. That means we no longer call component provision methods for simple expressions. (We also wrap more binding kinds in methods.)

See Javadoc for details.

RELNOTES=n/a

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=184836941
diff --git a/java/dagger/internal/codegen/MapBindingExpression.java b/java/dagger/internal/codegen/MapBindingExpression.java
index 5de5038..e8edefc 100644
--- a/java/dagger/internal/codegen/MapBindingExpression.java
+++ b/java/dagger/internal/codegen/MapBindingExpression.java
@@ -30,9 +30,8 @@
 import dagger.internal.MapBuilder;
 import dagger.model.BindingKind;
 import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
 import java.util.Collections;
-import java.util.Map;
+import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Elements;
 
@@ -44,20 +43,21 @@
   private final ProvisionBinding binding;
   private final ImmutableMap<DependencyRequest, ContributionBinding> dependencies;
   private final ComponentBindingExpressions componentBindingExpressions;
+  private final DaggerTypes types;
   private final Elements elements;
 
   MapBindingExpression(
       ResolvedBindings resolvedBindings,
-      RequestKind requestKind,
       BindingGraph graph,
       ComponentBindingExpressions componentBindingExpressions,
       DaggerTypes types,
       Elements elements) {
-    super(resolvedBindings, requestKind, types);
+    super(resolvedBindings);
     this.binding = (ProvisionBinding) resolvedBindings.contributionBinding();
     BindingKind bindingKind = this.binding.kind();
     checkArgument(bindingKind.equals(MULTIBOUND_MAP), bindingKind);
     this.componentBindingExpressions = componentBindingExpressions;
+    this.types = types;
     this.elements = elements;
     this.dependencies =
         Maps.toMap(
@@ -66,26 +66,24 @@
   }
 
   @Override
-  Expression getInstanceDependencyExpression(ClassName requestingClass) {
-    return Expression.create(binding.key().type(), mapExpression(requestingClass));
-  }
-
-  private CodeBlock mapExpression(ClassName requestingClass) {
+  Expression getDependencyExpression(ClassName requestingClass) {
     // TODO(ronshapiro): We should also make an ImmutableMap version of MapFactory
     boolean isImmutableMapAvailable = isImmutableMapAvailable();
     // TODO(ronshapiro, gak): Use Maps.immutableEnumMap() if it's available?
     if (isImmutableMapAvailable && dependencies.size() <= MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS) {
-      return CodeBlock.builder()
-          .add("$T.", ImmutableMap.class)
-          .add(maybeTypeParameters(requestingClass))
-          .add(
-              "of($L)",
-              dependencies
-                  .keySet()
-                  .stream()
-                  .map(dependency -> keyAndValueExpression(dependency, requestingClass))
-                  .collect(toParametersCodeBlock()))
-          .build();
+      return Expression.create(
+          immutableMapType(),
+          CodeBlock.builder()
+              .add("$T.", ImmutableMap.class)
+              .add(maybeTypeParameters(requestingClass))
+              .add(
+                  "of($L)",
+                  dependencies
+                      .keySet()
+                      .stream()
+                      .map(dependency -> keyAndValueExpression(dependency, requestingClass))
+                      .collect(toParametersCodeBlock()))
+              .build());
     }
     switch (dependencies.size()) {
       case 0:
@@ -110,10 +108,20 @@
         for (DependencyRequest dependency : dependencies.keySet()) {
           instantiation.add(".put($L)", keyAndValueExpression(dependency, requestingClass));
         }
-        return instantiation.add(".build()").build();
+        return Expression.create(
+            isImmutableMapAvailable ? immutableMapType() : binding.key().type(),
+            instantiation.add(".build()").build());
     }
   }
 
+  private DeclaredType immutableMapType() {
+    MapType mapType = MapType.from(binding.key());
+    return types.getDeclaredType(
+        elements.getTypeElement(ImmutableMap.class.getName()),
+        mapType.keyType(),
+        mapType.valueType());
+  }
+
   private CodeBlock keyAndValueExpression(DependencyRequest dependency, ClassName requestingClass) {
     return CodeBlock.of(
         "$L, $L",
@@ -123,13 +131,15 @@
             .codeBlock());
   }
 
-  private CodeBlock collectionsStaticFactoryInvocation(
+  private Expression collectionsStaticFactoryInvocation(
       ClassName requestingClass, CodeBlock methodInvocation) {
-    return CodeBlock.builder()
-        .add("$T.", Collections.class)
-        .add(maybeTypeParameters(requestingClass))
-        .add(methodInvocation)
-        .build();
+    return Expression.create(
+        binding.key().type(),
+        CodeBlock.builder()
+            .add("$T.", Collections.class)
+            .add(maybeTypeParameters(requestingClass))
+            .add(methodInvocation)
+            .build());
   }
 
   private CodeBlock maybeTypeParameters(ClassName requestingClass) {
@@ -143,15 +153,4 @@
   private boolean isImmutableMapAvailable() {
     return elements.getTypeElement(ImmutableMap.class.getCanonicalName()) != null;
   }
-
-  @Override
-  protected CodeBlock explicitTypeParameter(ClassName requestingClass) {
-    if (isImmutableMapAvailable()) {
-      TypeMirror keyType = binding.key().type();
-      return CodeBlock.of(
-          "<$T>",
-          isTypeAccessibleFrom(keyType, requestingClass.packageName()) ? keyType : Map.class);
-    }
-    return CodeBlock.of("");
-  }
 }