Automated g4 rollback of changelist 70734332.

*** Reason for rollback ***

Broke a project.

*** Original change description ***

Simplify OptionalBinder implementation to not delegate to a MapBinder.
Instead, bind directly to annotated @Actual/@Default keys.  This is in
preparation for future improvements.

This contains two logical changes:
1) The error message for duplicate actual/default bindings is now the default Guice message, instead of a custom thing in MapBinder.
2) getDependencies now returns the live dependency (either the actual or the default, not both).  Also, Optional<Provider<T>> continues to return a de...

***
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=70738452
diff --git a/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java b/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java
index 60c4f91..5d4447d 100644
--- a/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java
+++ b/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java
@@ -17,12 +17,14 @@
 package com.google.inject.multibindings;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.inject.internal.RehashableKeys.Keys.needsRehashing;
+import static com.google.inject.internal.RehashableKeys.Keys.rehash;
 import static com.google.inject.multibindings.Multibinder.checkConfiguration;
 import static com.google.inject.util.Types.newParameterizedType;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
 import com.google.inject.Binder;
 import com.google.inject.Binding;
 import com.google.inject.Inject;
@@ -32,9 +34,12 @@
 import com.google.inject.Provider;
 import com.google.inject.TypeLiteral;
 import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.internal.Errors;
+import com.google.inject.multibindings.Element.Type;
+import com.google.inject.multibindings.MapBinder.RealMapBinder;
 import com.google.inject.spi.BindingTargetVisitor;
 import com.google.inject.spi.Dependency;
-import com.google.inject.spi.Element;
+import com.google.inject.spi.HasDependencies;
 import com.google.inject.spi.ProviderInstanceBinding;
 import com.google.inject.spi.ProviderLookup;
 import com.google.inject.spi.ProviderWithDependencies;
@@ -42,14 +47,9 @@
 import com.google.inject.spi.Toolable;
 import com.google.inject.util.Types;
 
-import java.io.Serializable;
-import java.lang.annotation.Annotation;
-import java.lang.annotation.Retention;
-import java.lang.reflect.Type;
+import java.util.Map;
 import java.util.Set;
 
-import javax.inject.Qualifier;
-
 
 /**
  * An API to bind optional values, optionally with a default value.
@@ -168,12 +168,6 @@
     return (TypeLiteral<Optional<Provider<T>>>) TypeLiteral.get(Types.newParameterizedType(
         Optional.class, newParameterizedType(Provider.class, type.getType())));
   }
-  
-  @SuppressWarnings("unchecked")
-  static <T> Key<Provider<T>> providerOf(Key<T> key) {
-    Type providerT = Types.providerOf(key.getTypeLiteral().getType());
-    return (Key<Provider<T>>) key.ofType(providerT);
-  }
 
   /**
    * Returns a binding builder used to set the default value that will be injected.
@@ -195,18 +189,6 @@
   public abstract LinkedBindingBuilder<T> setBinding();
   
   enum Source { DEFAULT, ACTUAL }
-  
-  @Retention(RUNTIME)
-  @Qualifier
-  @interface Default {
-    String value();
-  }
-
-  @Retention(RUNTIME)
-  @Qualifier
-  @interface Actual {
-    String value();
-  }
 
   /**
    * The actual OptionalBinder plays several roles.  It implements Module to hide that
@@ -217,21 +199,18 @@
     private final Key<Optional<T>> optionalKey;
     private final Key<Optional<javax.inject.Provider<T>>> optionalJavaxProviderKey;
     private final Key<Optional<Provider<T>>> optionalProviderKey;
+    private final Key<Map<Source, Provider<T>>> mapKey;
+    private final RealMapBinder<Source, T> mapBinder;
+    private final Set<Dependency<?>> dependencies;
     private final Provider<Optional<Provider<T>>> optionalProviderT;
-    private final Key<T> defaultKey;
-    private final Key<T> actualKey;
+    
 
     /** the target injector's binder. non-null until initialization, null afterwards */
     private Binder binder;
     /** the default binding, for the SPI. */
-    private Binding<T> defaultBinding;
+    private Binding<?> defaultBinding;
     /** the actual binding, for the SPI */
-    private Binding<T> actualBinding;
-    
-    /** the dependencies -- initialized with defaults & overridden when tooled. */
-    private Set<Dependency<?>> dependencies;
-    /** the dependencies -- initialized with defaults & overridden when tooled. */
-    private Set<Dependency<?>> providerDependencies;
+    private Binding<?> actualBinding;
 
     private RealOptionalBinder(Binder binder, Key<T> typeKey) {
       this.binder = binder;
@@ -240,14 +219,26 @@
       this.optionalKey = typeKey.ofType(optionalOf(literal));
       this.optionalJavaxProviderKey = typeKey.ofType(optionalOfJavaxProvider(literal));
       this.optionalProviderKey = typeKey.ofType(optionalOfProvider(literal));
+      this.mapKey =
+          typeKey.ofType(MapBinder.mapOfProviderOf(TypeLiteral.get(Source.class), literal));
+      this.dependencies = ImmutableSet.<Dependency<?>>of(Dependency.get(mapKey));
       this.optionalProviderT = binder.getProvider(optionalProviderKey);
-      String name = RealElement.nameOf(typeKey);
-      this.defaultKey = Key.get(typeKey.getTypeLiteral(), new DefaultImpl(name));
-      this.actualKey = Key.get(typeKey.getTypeLiteral(), new ActualImpl(name));
-      this.dependencies = ImmutableSet.<Dependency<?>>of(
-          Dependency.get(defaultKey), Dependency.get(actualKey));
-      this.providerDependencies = ImmutableSet.<Dependency<?>>of(
-          Dependency.get(providerOf(defaultKey)), Dependency.get(providerOf(actualKey)));
+      if (typeKey.getAnnotation() != null) {
+        this.mapBinder = (RealMapBinder<Source, T>) MapBinder.newMapBinder(binder,
+            TypeLiteral.get(Source.class), typeKey.getTypeLiteral(), typeKey.getAnnotation());
+      } else if (typeKey.getAnnotationType() != null) {
+        this.mapBinder = (RealMapBinder<Source, T>) MapBinder.newMapBinder(binder,
+            TypeLiteral.get(Source.class), typeKey.getTypeLiteral(), typeKey.getAnnotationType());
+      } else {
+        this.mapBinder = (RealMapBinder<Source, T>) MapBinder.newMapBinder(binder,
+            TypeLiteral.get(Source.class), typeKey.getTypeLiteral());
+      }
+      mapBinder.updateDuplicateKeyMessage(Source.DEFAULT, "OptionalBinder for "
+          + Errors.convert(typeKey)
+          + " called with different setDefault values, from bindings:\n");
+      mapBinder.updateDuplicateKeyMessage(Source.ACTUAL, "OptionalBinder for "
+          + Errors.convert(typeKey)
+          + " called with different setBinding values, from bindings:\n");
     }
     
     /**
@@ -274,49 +265,82 @@
     }
 
     @Override public LinkedBindingBuilder<T> setDefault() {
-      checkConfiguration(!isInitialized(), "already initialized");      
+      checkConfiguration(!isInitialized(), "already initialized");
+      
       addDirectTypeBinding(binder);
-      return binder.bind(defaultKey);
+
+      RealElement.BindingBuilder<T> valueBinding = RealElement.addBinding(binder,
+          Element.Type.OPTIONALBINDER, typeKey.getTypeLiteral(), RealElement.nameOf(typeKey));
+      Key<T> valueKey = Key.get(typeKey.getTypeLiteral(), valueBinding.getAnnotation());
+      mapBinder.addBinding(Source.DEFAULT).toProvider(
+          new ValueProvider<T>(valueKey, binder.getProvider(valueKey)));
+      return valueBinding;
     }
 
     @Override public LinkedBindingBuilder<T> setBinding() {
-      checkConfiguration(!isInitialized(), "already initialized");      
+      checkConfiguration(!isInitialized(), "already initialized");
+      
       addDirectTypeBinding(binder);
-      return binder.bind(actualKey);
+
+      RealElement.BindingBuilder<T> valueBinding = RealElement.addBinding(binder,
+          Element.Type.OPTIONALBINDER, typeKey.getTypeLiteral(), RealElement.nameOf(typeKey));
+      Key<T> valueKey = Key.get(typeKey.getTypeLiteral(), valueBinding.getAnnotation());
+      mapBinder.addBinding(Source.ACTUAL).toProvider(
+          new ValueProvider<T>(valueKey, binder.getProvider(valueKey)));
+      return valueBinding;
+    }
+    
+    /**
+     * Traverses through the dependencies of the providers in order to get to the user's binding.
+     */
+    private Binding<?> getBindingFromMapProvider(Injector injector, Provider<T> mapProvider) {
+      HasDependencies deps = (HasDependencies) mapProvider;
+      Key<?> depKey = Iterables.getOnlyElement(deps.getDependencies()).getKey();
+      // The dep flow is (and will stay this way, until we change the internals) --
+      //    Key[type=Provider<java.lang.String>, annotation=@Element(type=MAPBINDER)]
+      // -> Key[type=String, annotation=@Element(type=MAPBINDER)]
+      // -> Key[type=Provider<String>, annotation=@Element(type=OPTIONALBINDER)]
+      // -> Key[type=String, annotation=@Element(type=OPTIONALBINDER)]
+      // The last one points to the user's binding.
+      for (int i = 0; i < 3; i++) {
+        deps = (HasDependencies) injector.getBinding(depKey);
+        depKey = Iterables.getOnlyElement(deps.getDependencies()).getKey();
+      }
+      return injector.getBinding(depKey);
     }
 
     public void configure(Binder binder) {
       checkConfiguration(!isInitialized(), "OptionalBinder was already initialized");
 
+      final Provider<Map<Source, Provider<T>>> mapProvider = binder.getProvider(mapKey);
       binder.bind(optionalProviderKey).toProvider(
           new RealOptionalBinderProviderWithDependencies<Optional<Provider<T>>>(typeKey) {
         private Optional<Provider<T>> optional;
 
         @Toolable @Inject void initialize(Injector injector) {
           RealOptionalBinder.this.binder = null;
-          actualBinding = injector.getExistingBinding(actualKey);
-          defaultBinding = injector.getExistingBinding(defaultKey);
-          Binding<T> binding = null;
-          if (actualBinding != null) {
-            // TODO(sameb): Consider exposing an option that will allow
-            // ACTUAL to fallback to DEFAULT if ACTUAL's provider returns null.
-            // Right now, an ACTUAL binding can convert from present -> absent
-            // if it's bound to a provider that returns null.
-            binding = actualBinding;
-          } else if (defaultBinding != null) {
-            binding = defaultBinding;
-          }
-          
-          if (binding != null) {
-            optional = Optional.of(binding.getProvider());
-            RealOptionalBinder.this.dependencies =
-                ImmutableSet.<Dependency<?>>of(Dependency.get(binding.getKey()));
-            RealOptionalBinder.this.providerDependencies = 
-                ImmutableSet.<Dependency<?>>of(Dependency.get(providerOf(binding.getKey())));
-          } else {            
-            optional = Optional.absent();
-            RealOptionalBinder.this.dependencies = ImmutableSet.of();
-            RealOptionalBinder.this.providerDependencies = ImmutableSet.of();
+          Map<Source, Provider<T>> map = mapProvider.get();
+          // Map might be null if duplicates prevented MapBinder from initializing
+          if (map != null) {
+            if (map.containsKey(Source.ACTUAL)) {
+              // TODO(sameb): Consider exposing an option that will allow
+              // ACTUAL to fallback to DEFAULT if ACTUAL's provider returns null.
+              // Right now, an ACTUAL binding can convert from present -> absent
+              // if it's bound to a provider that returns null.
+              optional = Optional.fromNullable(map.get(Source.ACTUAL)); 
+            } else if (map.containsKey(Source.DEFAULT)) {
+              optional = Optional.fromNullable(map.get(Source.DEFAULT));
+            } else {
+              optional = Optional.absent();
+            }
+            
+            // Also set up the bindings for the SPI.
+            if (map.containsKey(Source.ACTUAL)) {
+              actualBinding = getBindingFromMapProvider(injector, map.get(Source.ACTUAL));
+            }
+            if (map.containsKey(Source.DEFAULT)) {
+              defaultBinding = getBindingFromMapProvider(injector, map.get(Source.DEFAULT));
+            }
           }
         }
         
@@ -325,7 +349,7 @@
         }
 
         public Set<Dependency<?>> getDependencies() {
-          return providerDependencies;
+          return dependencies;
         }
       });
       
@@ -344,7 +368,7 @@
             OptionalBinderBinding<Optional<T>>,
             Provider<Optional<T>> {
       RealOptionalKeyProvider() {
-        super(typeKey);
+        super(mapKey);
       }
       
       public Optional<T> get() {
@@ -392,27 +416,30 @@
         }
       }
 
-      public boolean containsElement(Element element) {
-        Key<?> elementKey;
-        if (element instanceof Binding) {
-          elementKey = ((Binding<?>) element).getKey();
-        } else if (element instanceof ProviderLookup) {
-          elementKey = ((ProviderLookup<?>) element).getKey();
+      public boolean containsElement(com.google.inject.spi.Element element) {
+        if (mapBinder.containsElement(element)) {
+          return true;
         } else {
-          return false; // cannot match;
-        }
+          Key<?> elementKey;
+          if (element instanceof Binding) {
+            elementKey = ((Binding<?>) element).getKey();
+          } else if (element instanceof ProviderLookup) {
+            elementKey = ((ProviderLookup<?>) element).getKey();
+          } else {
+            return false; // cannot match;
+          }
 
-        return elementKey.equals(optionalKey)
-            || elementKey.equals(optionalProviderKey)
-            || elementKey.equals(optionalJavaxProviderKey)
-            || elementKey.equals(defaultKey)
-            || elementKey.equals(actualKey)
-            || matchesTypeKey(element, elementKey);
+          return elementKey.equals(optionalKey)
+              || elementKey.equals(optionalProviderKey)
+              || elementKey.equals(optionalJavaxProviderKey)
+              || matchesTypeKey(element, elementKey)
+              || matchesUserBinding(elementKey);
+        }
       }
     }
     
     /** Returns true if the key & element indicate they were bound by this OptionalBinder. */
-    private boolean matchesTypeKey(Element element, Key<?> elementKey) {
+    private boolean matchesTypeKey(com.google.inject.spi.Element element, Key<?> elementKey) {
       // Just doing .equals(typeKey) isn't enough, because the user can bind that themselves.
       return elementKey.equals(typeKey)
           && element instanceof ProviderInstanceBinding
@@ -420,17 +447,73 @@
               .getUserSuppliedProvider() instanceof RealOptionalBinderProviderWithDependencies);
     }
 
+    /** Returns true if the key indicates this is a user bound value for the optional binder. */
+    private boolean matchesUserBinding(Key<?> elementKey) {
+      return elementKey.getAnnotation() instanceof Element
+          && ((Element) elementKey.getAnnotation()).setName().equals(RealElement.nameOf(typeKey))
+          && ((Element) elementKey.getAnnotation()).type() == Type.OPTIONALBINDER
+          && elementKey.getTypeLiteral().equals(typeKey.getTypeLiteral());
+    }
+
     private boolean isInitialized() {
       return binder == null;
     }
 
     @Override public boolean equals(Object o) {
       return o instanceof RealOptionalBinder
-          && ((RealOptionalBinder<?>) o).typeKey.equals(typeKey);
+          && ((RealOptionalBinder<?>) o).mapKey.equals(mapKey);
     }
 
     @Override public int hashCode() {
-      return typeKey.hashCode();
+      return mapKey.hashCode();
+    }
+
+    /** A Provider that bases equality & hashcodes off another key. */
+    private static final class ValueProvider<T> implements ProviderWithDependencies<T> {
+      private final Provider<T> provider;
+      private volatile Key<T> key;
+
+      private ValueProvider(Key<T> key, Provider<T> provider) {
+        this.key = key;
+        this.provider = provider;
+      }
+      
+      public T get() {
+        return provider.get();
+      }
+      
+      public Set<Dependency<?>> getDependencies() {
+        return ((HasDependencies) provider).getDependencies();
+      }
+
+      private Key<T> getCurrentKey() {
+        // Every time, check if the key needs rehashing.
+        // If so, update the field as an optimization for next time.
+        Key<T> currentKey = key;
+        if (needsRehashing(currentKey)) {
+          currentKey = rehash(currentKey);
+          key = currentKey;
+        }
+        return currentKey;
+      }
+
+      /**
+       * Equality is based on the key (which includes the target information, because of how
+       * RealElement works). This lets duplicate bindings collapse.
+       */
+      @Override public boolean equals(Object obj) {
+        return obj instanceof ValueProvider
+            && getCurrentKey().equals(((ValueProvider) obj).getCurrentKey());
+      }
+
+      /** We only use the hashcode of the typeliteral, which can't change. */
+      @Override public int hashCode() {
+        return key.getTypeLiteral().hashCode();
+      }
+
+      @Override public String toString() {
+        return provider.toString();
+      }
     }
 
     /**
@@ -456,55 +539,4 @@
       }
     }
   }
-  
-  static class DefaultImpl extends BaseAnnotation implements Default {
-    public DefaultImpl(String value) {
-      super(Default.class, value);
-    }
-  }
-  
-  static class ActualImpl extends BaseAnnotation implements Actual {
-    public ActualImpl(String value) {
-      super(Actual.class, value);
-    }
-  }
-  
-  abstract static class BaseAnnotation implements Serializable, Annotation {
-
-    private final String value;
-    private final Class<? extends Annotation> clazz;
-
-    BaseAnnotation(Class<? extends Annotation> clazz, String value) {
-      this.clazz = checkNotNull(clazz, "clazz");
-      this.value = checkNotNull(value, "value");
-    }
-
-    public String value() {
-      return this.value;
-    }
-
-    @Override public int hashCode() {
-      // This is specified in java.lang.Annotation.
-      return (127 * "value".hashCode()) ^ value.hashCode();
-    }
-
-    @Override public boolean equals(Object o) {
-      if (!(clazz.isInstance(o))) {
-        return false;
-      }
-
-      BaseAnnotation other = (BaseAnnotation) o;
-      return value.equals(other.value());
-    }
-
-    @Override public String toString() {
-      return "@" + clazz.getName() + (value.isEmpty() ? "" : "(value=" + value + ")");
-    }
-
-    @Override public Class<? extends Annotation> annotationType() {
-      return clazz;
-    }
-
-    private static final long serialVersionUID = 0;
-  }
 }
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java b/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
index 2529c18..246c7a3 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
@@ -43,8 +43,6 @@
 import com.google.inject.Scopes;
 import com.google.inject.TypeLiteral;
 import com.google.inject.internal.RehashableKeys;
-import com.google.inject.multibindings.OptionalBinder.Actual;
-import com.google.inject.multibindings.OptionalBinder.Default;
 import com.google.inject.multibindings.SpiUtils.VisitType;
 import com.google.inject.name.Named;
 import com.google.inject.name.Names;
@@ -347,10 +345,11 @@
     } catch (CreationException ce) {
       assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
       assertContains(ce.getMessage(),
-          "1) A binding to java.lang.String annotated with @" 
-              + Default.class.getName() + " was already configured at "
-              + module.getClass().getName() + ".configure(",
-          "at " + module.getClass().getName() + ".configure(");
+          "1) OptionalBinder for java.lang.String called with different setDefault values, " 
+              + "from bindings:",
+          "at " + module.getClass().getName() + ".configure(",
+          "at " + module.getClass().getName() + ".configure(",
+          "at " + MapBinder.RealMapBinder.class.getName());
     }
   }  
   
@@ -367,10 +366,11 @@
     } catch (CreationException ce) {
       assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
       assertContains(ce.getMessage(),
-          "1) A binding to java.lang.String annotated with @" 
-              + Actual.class.getName() + " was already configured at "
-              + module.getClass().getName() + ".configure(",
-          "at " + module.getClass().getName() + ".configure(");
+          "1) OptionalBinder for java.lang.String called with different setBinding values, " 
+              + "from bindings:",
+          "at " + module.getClass().getName() + ".configure(",
+          "at " + module.getClass().getName() + ".configure(",
+          "at " + MapBinder.RealMapBinder.class.getName());
     }
   }  
   
@@ -387,16 +387,17 @@
       Guice.createInjector(module);
       fail();
     } catch (CreationException ce) {
-      assertEquals(ce.getMessage(), 2, ce.getErrorMessages().size());      
+      assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
       assertContains(ce.getMessage(),
-          "1) A binding to java.lang.String annotated with @"
-              + Default.class.getName() + " was already configured at "
-              + module.getClass().getName() + ".configure(",
+          "1) OptionalBinder for java.lang.String called with different setDefault values, " 
+              + "from bindings:",
           "at " + module.getClass().getName() + ".configure(",
-          "2) A binding to java.lang.String annotated with @"
-              + Actual.class.getName() + " was already configured at "
-              + module.getClass().getName() + ".configure(",
-          "at " + module.getClass().getName() + ".configure(");
+          "at " + module.getClass().getName() + ".configure(",
+          "and OptionalBinder for java.lang.String called with different setBinding values, " 
+              + "from bindings:",
+          "at " + module.getClass().getName() + ".configure(",
+          "at " + module.getClass().getName() + ".configure(",
+          "at " + MapBinder.RealMapBinder.class.getName());
     }
   }
   
@@ -448,27 +449,17 @@
   }
   
   public void testMultipleDifferentOptionals() {
-    final Key<String> bKey = Key.get(String.class, named("b"));
-    final Key<String> cKey = Key.get(String.class, named("c"));
     Module module = new AbstractModule() {
       @Override protected void configure() {
         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
         OptionalBinder.newOptionalBinder(binder(), Integer.class).setDefault().toInstance(1);
-        
-        OptionalBinder.newOptionalBinder(binder(), bKey).setDefault().toInstance("b");
-        OptionalBinder.newOptionalBinder(binder(), cKey).setDefault().toInstance("c");
       }
     };
     Injector injector = Guice.createInjector(module);
     assertEquals("a", injector.getInstance(String.class));
     assertEquals(1, injector.getInstance(Integer.class).intValue());
-    assertEquals("b", injector.getInstance(bKey));
-    assertEquals("c", injector.getInstance(cKey));
     
-    assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 3, instance("a"), null);
-    assertOptionalVisitor(intKey, setOf(module), VisitType.BOTH, 3, instance(1), null);
-    assertOptionalVisitor(bKey, setOf(module), VisitType.BOTH, 3, instance("b"), null);
-    assertOptionalVisitor(cKey, setOf(module), VisitType.BOTH, 3, instance("c"), null);
+    assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 1, instance("a"), null);
   }
   
   public void testOptionalIsAppropriatelyLazy() {
@@ -613,7 +604,7 @@
     }
   }
 
-  public void testDependencies_both() {
+  public void testDependencies() {
     Injector injector = Guice.createInjector(new AbstractModule() {
       @Override protected void configure() {
         OptionalBinder<String> optionalbinder =
@@ -628,40 +619,7 @@
     HasDependencies withDependencies = (HasDependencies) binding;
     Set<String> elements = Sets.newHashSet();
     elements.addAll(recurseForDependencies(injector, withDependencies));
-    assertEquals(ImmutableSet.of("B"), elements);
-  }
-
-  public void testDependencies_actual() {
-    Injector injector = Guice.createInjector(new AbstractModule() {
-      @Override protected void configure() {
-        OptionalBinder<String> optionalbinder =
-            OptionalBinder.newOptionalBinder(binder(), String.class);
-        optionalbinder.setBinding().to(Key.get(String.class, Names.named("b")));
-        bindConstant().annotatedWith(Names.named("b")).to("B");
-      }
-    });
-
-    Binding<String> binding = injector.getBinding(Key.get(String.class));
-    HasDependencies withDependencies = (HasDependencies) binding;
-    Set<String> elements = Sets.newHashSet();
-    elements.addAll(recurseForDependencies(injector, withDependencies));
-    assertEquals(ImmutableSet.of("B"), elements);
-  }
-
-  public void testDependencies_default() {
-    Injector injector = Guice.createInjector(new AbstractModule() {
-      @Override protected void configure() {
-        OptionalBinder<String> optionalbinder =
-            OptionalBinder.newOptionalBinder(binder(), String.class);
-        optionalbinder.setDefault().toInstance("A");
-      }
-    });
-
-    Binding<String> binding = injector.getBinding(Key.get(String.class));
-    HasDependencies withDependencies = (HasDependencies) binding;
-    Set<String> elements = Sets.newHashSet();
-    elements.addAll(recurseForDependencies(injector, withDependencies));
-    assertEquals(ImmutableSet.of("A"), elements);
+    assertEquals(ImmutableSet.of("A", "B"), elements);
   }
   
   private Set<String> recurseForDependencies(Injector injector, HasDependencies hasDependencies) {
@@ -920,6 +878,7 @@
     list.add("C");
     Key<?> keyAfter = binding.getKey();
     assertSame(keyBefore, keyAfter);
+    assertTrue(RehashableKeys.Keys.needsRehashing(keyAfter));
   }
 
   @BindingAnnotation
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java b/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
index 9517425..d121944 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
@@ -16,6 +16,7 @@
 
 package com.google.inject.multibindings;
 
+import static com.google.common.collect.Iterables.getOnlyElement;
 import static com.google.inject.multibindings.MapBinder.entryOfProviderOf;
 import static com.google.inject.multibindings.MapBinder.mapOf;
 import static com.google.inject.multibindings.MapBinder.mapOfJavaxProviderOf;
@@ -53,12 +54,14 @@
 import com.google.inject.spi.DefaultBindingTargetVisitor;
 import com.google.inject.spi.Element;
 import com.google.inject.spi.Elements;
+import com.google.inject.spi.HasDependencies;
 import com.google.inject.spi.InstanceBinding;
 import com.google.inject.spi.LinkedKeyBinding;
 import com.google.inject.spi.ProviderInstanceBinding;
 import com.google.inject.spi.ProviderKeyBinding;
 import com.google.inject.spi.ProviderLookup;
 
+import java.lang.reflect.ParameterizedType;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -523,11 +526,16 @@
         keyType.ofType(optionalOfJavaxProvider(keyType.getTypeLiteral()));
     Key<Optional<Provider<T>>> optionalProviderKey =
         keyType.ofType(optionalOfProvider(keyType.getTypeLiteral()));
+    Binding<Map<Source, T>> mapBinding = injector.getBinding(
+        keyType.ofType(mapOf(TypeLiteral.get(Source.class), keyType.getTypeLiteral())));
+    MapBinderBinding<Map<Source, T>> mapbinderBinding = (MapBinderBinding<
+        Map<Source, T>>) mapBinding.acceptTargetVisitor(new Visitor<Map<Source, T>>());
 
     boolean keyMatch = false;
     boolean optionalKeyMatch = false;
     boolean optionalJavaxProviderKeyMatch = false;
     boolean optionalProviderKeyMatch = false;
+    boolean mapBindingMatch = false;
     boolean defaultMatch = false;
     boolean actualMatch = false;
     List<Object> otherOptionalBindings = Lists.newArrayList();
@@ -558,12 +566,19 @@
       } else if (b.getKey().equals(optionalProviderKey)) {
         assertTrue(contains);
         optionalProviderKeyMatch = true;
+      } else if (b.getKey().equals(mapBinding.getKey())) {
+        assertTrue(contains);
+        mapBindingMatch = true;
+        // Validate that this binding is also a MapBinding.
+        assertEquals(mapbinderBinding, b.acceptTargetVisitor(visitor));
       } else if (expectedDefault != null && matches(b, expectedDefault)) {
         assertTrue(contains);
         defaultMatch = true;
       } else if (expectedActual != null && matches(b, expectedActual)) {
         assertTrue(contains);
         actualMatch = true;
+      } else if (mapbinderBinding.containsElement(b)) {
+        assertTrue(contains);
       } else if (contains) {
         otherMatches.add(b);
       }
@@ -575,6 +590,7 @@
     assertTrue(optionalKeyMatch);
     assertTrue(optionalJavaxProviderKeyMatch);
     assertTrue(optionalProviderKeyMatch);
+    assertTrue(mapBindingMatch);
     assertEquals(expectedDefault != null, defaultMatch);
     assertEquals(expectedActual != null, actualMatch);
     assertEquals("other OptionalBindings found: " + otherOptionalBindings,
@@ -589,22 +605,27 @@
     Map<Key<?>, Binding<?>> indexed = index(elements);
     Key<Optional<T>> optionalKey =
         keyType.ofType(OptionalBinder.optionalOf(keyType.getTypeLiteral()));
+    Key<Map<Source, T>> sourceMapKey =
+        keyType.ofType(mapOf(TypeLiteral.get(Source.class), keyType.getTypeLiteral()));
     Visitor<Optional<T>> visitor = new Visitor<Optional<T>>();
     OptionalBinderBinding<T> optionalBinder = null;
+    MapBinderBinding<Map<Source, T>> mapbinderBinding = null;
     Key<?> defaultKey = null;
     Key<?> actualKey = null;
 
     Binding optionalBinding = indexed.get(optionalKey);
     optionalBinder = (OptionalBinderBinding<T>) optionalBinding.acceptTargetVisitor(visitor);
+    Binding mapBinding = indexed.get(sourceMapKey);
+    mapbinderBinding = (MapBinderBinding<Map<Source, T>>) mapBinding.acceptTargetVisitor(visitor);
 
     // Locate the defaultKey & actualKey
     for (Element element : elements) {
       if (optionalBinder.containsElement(element) && element instanceof Binding) {
         Binding binding = (Binding) element;
         if (isSourceEntry(binding, Source.DEFAULT)) {
-          defaultKey = binding.getKey();
+          defaultKey = keyFromOptionalSourceBinding(binding, indexed);
         } else if (isSourceEntry(binding, Source.ACTUAL)) {
-          actualKey = binding.getKey();
+          actualKey = keyFromOptionalSourceBinding(binding, indexed);
         }
       }
     }
@@ -620,6 +641,7 @@
     boolean optionalKeyMatch = false;
     boolean optionalJavaxProviderKeyMatch = false;
     boolean optionalProviderKeyMatch = false;
+    boolean mapBindingMatch = false;
     boolean defaultMatch = false;
     boolean actualMatch = false;
     List<Object> otherOptionalElements = Lists.newArrayList();
@@ -663,6 +685,11 @@
       } else if (key != null && key.equals(optionalProviderKey)) {
         assertTrue(contains);
         optionalProviderKeyMatch = true;
+      } else if (key != null && key.equals(sourceMapKey)) {
+        assertTrue(contains);
+        mapBindingMatch = true;
+        // Validate that this binding is also a MapBinding.
+        assertEquals(mapbinderBinding, b.acceptTargetVisitor(visitor));
       } else if (key != null && key.equals(defaultKey)) {
         assertTrue(contains);
         if (b != null) { // otherwise it might just be a ProviderLookup into it
@@ -676,6 +703,8 @@
           assertTrue("expected: " + expectedActual + ", but was: " + b, matches(b, expectedActual));
           actualMatch = true;
         }
+      } else if (mapbinderBinding.containsElement(element)) {
+        assertTrue(contains);
       } else if (contains) {
         otherContains.add(element);
       }
@@ -686,6 +715,7 @@
     assertTrue(optionalKeyMatch);
     assertTrue(optionalJavaxProviderKeyMatch);
     assertTrue(optionalProviderKeyMatch);
+    assertTrue(mapBindingMatch);
     assertEquals(expectedDefault != null, defaultMatch);
     assertEquals(expectedActual != null, actualMatch);
     assertEquals(otherContains.toString(), 0, otherContains.size());
@@ -695,16 +725,40 @@
      // Validate that we can construct an injector out of the remaining bindings.
     Guice.createInjector(Elements.getModule(nonContainedElements));
   }
+  
+  private static Key<?> keyFromOptionalSourceBinding(Binding<?> binding,
+      Map<Key<?>, Binding<?>> elements) {
+    // Flow is:
+    //  binding == ProviderInstanceBinding<Map.Entry<Source, Provider<String>>
+    //   dependency on: Provider<String> that maps to ProviderInstanceBinding<String> in MapBinder
+    //      dependency on: Provider<String> of user set value.
+    Key<?> mapKey =
+        genericOf(getOnlyElement(((HasDependencies) binding).getDependencies()).getKey());
+    Binding<?> mapBinding = elements.get(mapKey);
+    Key<?> userKey =
+        genericOf(getOnlyElement(((HasDependencies) mapBinding).getDependencies()).getKey());
+    return userKey;
+  }
+
+  /** Returns {@code Key<T>} for something like {@code Key<Provider<T>>} */
+  private static Key<?> genericOf(Key<?> key) {
+    ParameterizedType type = (ParameterizedType) key.getTypeLiteral().getType();
+    assertEquals(1, type.getActualTypeArguments().length);
+    Key<?> result = key.ofType(type.getActualTypeArguments()[0]);
+    return result;
+  }
 
   private static boolean isSourceEntry(Binding b, Source type) {
-    switch(type) {
-      case ACTUAL:
-        return b.getKey().getAnnotation() instanceof OptionalBinder.Actual;
-      case DEFAULT:
-        return b.getKey().getAnnotation() instanceof OptionalBinder.Default;
-      default:
-        throw new IllegalStateException("invalid type: " + type);
+    if (b instanceof ProviderInstanceBinding && b.getKey().getAnnotation() instanceof RealElement) {
+      javax.inject.Provider provider = ((ProviderInstanceBinding) b).getUserSuppliedProvider();
+      if (provider instanceof Map.Entry) {
+        Map.Entry entry = (Map.Entry) provider;
+        if (entry.getKey() == type) {
+          return true;
+        }
+      }
     }
+    return false;
   }
 
   /** Returns the subset of elements that have keys, indexed by them. */