Add support for ProvisionListeners to notify on toInstance & constant bindings.

---------------------
Manually synced.
COMMIT=41634417
diff --git a/core/src/com/google/inject/internal/AbstractBindingProcessor.java b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
index f09c40b..72dae2b 100644
--- a/core/src/com/google/inject/internal/AbstractBindingProcessor.java
+++ b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
@@ -26,6 +26,7 @@
 import com.google.inject.Module;
 import com.google.inject.Provider;
 import com.google.inject.Scope;
+import com.google.inject.Stage;
 import com.google.inject.TypeLiteral;
 import com.google.inject.spi.DefaultBindingTargetVisitor;
 
@@ -51,8 +52,8 @@
       Module.class,
       Provider.class,
       Scope.class,
+      Stage.class,
       TypeLiteral.class);
-  // TODO(jessewilson): fix BuiltInModule, then add Stage
   
   protected final ProcessedBindingData bindingData;
   
diff --git a/core/src/com/google/inject/internal/BindingProcessor.java b/core/src/com/google/inject/internal/BindingProcessor.java
index a87e326..7ce3ea0 100644
--- a/core/src/com/google/inject/internal/BindingProcessor.java
+++ b/core/src/com/google/inject/internal/BindingProcessor.java
@@ -87,8 +87,10 @@
         prepareBinding();
         Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
         T instance = binding.getInstance();
+        @SuppressWarnings("unchecked") // safe to cast to binding<T> because
+                                       // the processor was constructed w/ it
         Initializable<T> ref = initializer.requestInjection(
-            injector, instance, key, source, injectionPoints);
+            injector, instance, (Binding<T>) binding, source, injectionPoints);
         ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
         InternalFactory<? extends T> scopedFactory
             = Scoping.scope(key, injector, factory, source, scoping);
diff --git a/core/src/com/google/inject/internal/Initializer.java b/core/src/com/google/inject/internal/Initializer.java
index 33dee8d..56c6873 100644
--- a/core/src/com/google/inject/internal/Initializer.java
+++ b/core/src/com/google/inject/internal/Initializer.java
@@ -21,6 +21,7 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.inject.Binding;
 import com.google.inject.Key;
 import com.google.inject.Stage;
 import com.google.inject.TypeLiteral;
@@ -57,21 +58,25 @@
    *
    * @param instance an instance that optionally has members to be injected (each annotated with
    *      @Inject).
-   * @param key a key to use for keeping the state of the dependency chain
+   * @param binding the binding that caused this initializable to be created, if it exists.
    * @param source the source location that this injection was requested
    */
-  <T> Initializable<T> requestInjection(InjectorImpl injector, T instance, Key<T> key,
+  <T> Initializable<T> requestInjection(InjectorImpl injector, T instance, Binding<T> binding,
       Object source, Set<InjectionPoint> injectionPoints) {
     checkNotNull(source);
 
-    // short circuit if the object has no injections
-    if (instance == null
-        || (injectionPoints.isEmpty() && !injector.membersInjectorStore.hasTypeListeners())) {
+    ProvisionListenerStackCallback<T> provisionCallback =
+        binding == null ? null : injector.provisionListenerStore.get(binding);
+
+    // short circuit if the object has no injections or listeners.
+    if (instance == null || (injectionPoints.isEmpty()
+        && !injector.membersInjectorStore.hasTypeListeners()
+        && (provisionCallback == null || !provisionCallback.hasListeners()))) {
       return Initializables.of(instance);
     }
 
-    InjectableReference<T> initializable =
-        new InjectableReference<T>(injector, instance, key, source);
+    InjectableReference<T> initializable = new InjectableReference<T>(
+        injector, instance, binding == null ? null : binding.getKey(), provisionCallback, source);
     pendingInjection.put(instance, initializable);
     return initializable;
   }
@@ -118,10 +123,13 @@
     private final T instance;
     private final Object source;
     private final Key<T> key;
+    private final ProvisionListenerStackCallback<T> provisionCallback;
 
-    public InjectableReference(InjectorImpl injector, T instance, Key<T> key, Object source) {
+    public InjectableReference(InjectorImpl injector, T instance, Key<T> key,
+        ProvisionListenerStackCallback<T> provisionCallback, Object source) {
       this.injector = injector;
       this.key = key; // possibly null!
+      this.provisionCallback = provisionCallback; // possibly null!
       this.instance = checkNotNull(instance, "instance");
       this.source = checkNotNull(source, "source");
     }
@@ -163,7 +171,11 @@
         
         // if in Stage.TOOL, we only want to inject & notify toolable injection points.
         // (otherwise we'll inject all of them)
-        membersInjector.injectAndNotify(instance, errors.withSource(source), key, source, 
+        membersInjector.injectAndNotify(instance,
+            errors.withSource(source),
+            key,
+            provisionCallback,
+            source,
             injector.options.stage == Stage.TOOL);
       }
 
diff --git a/core/src/com/google/inject/internal/InjectorShell.java b/core/src/com/google/inject/internal/InjectorShell.java
index 4985f8c..043fdcf 100644
--- a/core/src/com/google/inject/internal/InjectorShell.java
+++ b/core/src/com/google/inject/internal/InjectorShell.java
@@ -129,9 +129,9 @@
       checkState(privateElements == null || parent != null, "PrivateElements with no parent");
       checkState(state != null, "no state. Did you remember to lock() ?");
 
-      // bind Stage and Singleton if this is a top-level injector
+      // bind Singleton if this is a top-level injector
       if (parent == null) {
-        modules.add(0, new RootModule(stage));
+        modules.add(0, new RootModule());
       }
       elements.addAll(Elements.getElements(stage, modules));
       
@@ -174,6 +174,7 @@
       new TypeConverterBindingProcessor(errors).process(injector, elements);
       stopwatch.resetAndLog("Converters creation");
 
+      bindStage(injector, stage);
       bindInjector(injector);
       bindLogger(injector);
       
@@ -270,16 +271,21 @@
     }
   }
 
-  private static class RootModule implements Module {
-    final Stage stage;
-
-    private RootModule(Stage stage) {
-      this.stage = checkNotNull(stage, "stage");
+  private static void bindStage(InjectorImpl injector, Stage stage) {
+    Key<Stage> key = Key.get(Stage.class);
+    InstanceBindingImpl<Stage> stageBinding = new InstanceBindingImpl<Stage>(
+        injector,
+        key,
+        SourceProvider.UNKNOWN_SOURCE,
+        new ConstantFactory<Stage>(Initializables.of(stage)),
+        ImmutableSet.<InjectionPoint>of(),
+        stage);
+    injector.state.putBinding(key, stageBinding);
     }
 
+  private static class RootModule implements Module {
     public void configure(Binder binder) {
       binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
-      binder.bind(Stage.class).toInstance(stage);
       binder.bindScope(Singleton.class, SINGLETON);
       binder.bindScope(javax.inject.Singleton.class, SINGLETON);
     }
diff --git a/core/src/com/google/inject/internal/MembersInjectorImpl.java b/core/src/com/google/inject/internal/MembersInjectorImpl.java
index d405de5..efb8c52 100644
--- a/core/src/com/google/inject/internal/MembersInjectorImpl.java
+++ b/core/src/com/google/inject/internal/MembersInjectorImpl.java
@@ -21,6 +21,7 @@
 import com.google.inject.Key;
 import com.google.inject.MembersInjector;
 import com.google.inject.TypeLiteral;
+import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
 import com.google.inject.spi.InjectionListener;
 import com.google.inject.spi.InjectionPoint;
 
@@ -58,7 +59,7 @@
   public void injectMembers(T instance) {
     Errors errors = new Errors(typeLiteral);
     try {
-      injectAndNotify(instance, errors, null, typeLiteral, false);
+      injectAndNotify(instance, errors, null, null, typeLiteral, false);
     } catch (ErrorsException e) {
       errors.merge(e.getErrors());
     }
@@ -66,18 +67,31 @@
     errors.throwProvisionExceptionIfErrorsExist();
   }
 
-  void injectAndNotify(final T instance, final Errors errors,
-      final Key<T> key, final Object source, final boolean toolableOnly)
-      throws ErrorsException {
+  void injectAndNotify(final T instance,
+      final Errors errors,
+      final Key<T> key, // possibly null!
+      final ProvisionListenerStackCallback<T> provisionCallback, // possibly null!
+      final Object source,
+      final boolean toolableOnly) throws ErrorsException {
     if (instance == null) {
       return;
     }
 
     injector.callInContext(new ContextualCallable<Void>() {
-      public Void call(InternalContext context) throws ErrorsException {
+      @Override
+      public Void call(final InternalContext context) throws ErrorsException {
         context.pushState(key, source);
         try {
+          if (provisionCallback != null && provisionCallback.hasListeners()) {
+            provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
+              @Override public T call() {
           injectMembers(instance, errors, context, toolableOnly);
+                return instance;
+              }
+            });
+          } else {
+            injectMembers(instance, errors, context, toolableOnly);
+          }
         } finally {
           context.popState();
         }
diff --git a/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java b/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java
index 8b2ed60..631a05f 100644
--- a/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java
+++ b/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java
@@ -18,15 +18,20 @@
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.MapMaker;
 import com.google.inject.Binding;
+import com.google.inject.Injector;
 import com.google.inject.Key;
+import com.google.inject.Stage;
 import com.google.inject.spi.ProvisionListener;
 import com.google.inject.spi.ProvisionListenerBinding;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
 
 /**
  * {@link ProvisionListenerStackCallback} for each key.
@@ -34,6 +39,12 @@
  * @author sameb@google.com (Sam Berlin)
  */
 final class ProvisionListenerCallbackStore {
+
+  // TODO(sameb): Consider exposing this in the API somehow?  Maybe?
+  // Lots of code often want to skip over the internal stuffs.
+  private static final Set<Key<?>> INTERNAL_BINDINGS =
+      ImmutableSet.of(Key.get(Injector.class), Key.get(Stage.class), Key.get(Logger.class));
+  
   private final ImmutableList<ProvisionListenerBinding> listenerBindings;
 
   private final Map<KeyBinding, ProvisionListenerStackCallback<?>> cache
@@ -52,7 +63,12 @@
    */
   @SuppressWarnings("unchecked") // the ProvisionListenerStackCallback type always agrees with the passed type
   public <T> ProvisionListenerStackCallback<T> get(Binding<T> binding) {
-    return (ProvisionListenerStackCallback<T>) cache.get(new KeyBinding(binding.getKey(), binding));
+    // Never notify any listeners for internal bindings.
+    if (!INTERNAL_BINDINGS.contains(binding.getKey())) {
+      return (ProvisionListenerStackCallback<T>) cache.get(
+          new KeyBinding(binding.getKey(), binding));
+    }
+    return ProvisionListenerStackCallback.emptyListener();
   }
 
   /**
@@ -82,8 +98,10 @@
         listeners.addAll(provisionBinding.getListeners());
       }
     }
-    if (listeners == null) {
-      listeners = ImmutableList.of();
+    if (listeners == null || listeners.isEmpty()) {
+      // Optimization: don't bother constructing the callback if there are
+      // no listeners.
+      return ProvisionListenerStackCallback.emptyListener();
     }
     return new ProvisionListenerStackCallback<T>(binding, listeners);
   }
diff --git a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
index 4870ca6..bfcf931 100644
--- a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
+++ b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
@@ -16,6 +16,7 @@
 
 package com.google.inject.internal;
 
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Binding;
 import com.google.inject.ProvisionException;
 import com.google.inject.spi.DependencyAndSource;
@@ -31,9 +32,18 @@
 final class ProvisionListenerStackCallback<T> {
 
   private static final ProvisionListener EMPTY_LISTENER[] = new ProvisionListener[0]; 
+  @SuppressWarnings("rawtypes")
+  private static final ProvisionListenerStackCallback<?> EMPTY_CALLBACK =
+      new ProvisionListenerStackCallback(null /* unused, so ok */, ImmutableList.of());
+
   private final ProvisionListener[] listeners;
   private final Binding<T> binding;
 
+  @SuppressWarnings("unchecked")
+  public static <T> ProvisionListenerStackCallback<T> emptyListener() {
+    return (ProvisionListenerStackCallback<T>) EMPTY_CALLBACK;
+  }
+
   public ProvisionListenerStackCallback(Binding<T> binding, List<ProvisionListener> listeners) {
     this.binding = binding;
     if (listeners.isEmpty()) {
diff --git a/core/src/com/google/inject/spi/ProvisionListener.java b/core/src/com/google/inject/spi/ProvisionListener.java
index 4f523f6..e3f06bd 100644
--- a/core/src/com/google/inject/spi/ProvisionListener.java
+++ b/core/src/com/google/inject/spi/ProvisionListener.java
@@ -35,7 +35,9 @@
    * Invoked by Guice when an object requires provisioning. Provisioning occurs
    * when Guice locates and injects the dependencies for a binding. For types
    * bound to a Provider, provisioning encapsulates the {@link Provider#get}
-   * method. For other types, provisioning encapsulates the construction of the
+   * method. For toInstance or constant bindings, provisioning encapsulates
+   * the injecting of {@literal @}{@code Inject}ed fields or methods.
+   * For other types, provisioning encapsulates the construction of the
    * object. If a type is bound within a {@link Scope}, provisioning depends on
    * the scope. Types bound in Singleton scope will only be provisioned once.
    * Types bound in no scope will be provisioned every time they are injected.
diff --git a/core/test/com/google/inject/BinderTest.java b/core/test/com/google/inject/BinderTest.java
index 193bbad..b52a153 100644
--- a/core/test/com/google/inject/BinderTest.java
+++ b/core/test/com/google/inject/BinderTest.java
@@ -456,6 +456,7 @@
           bind(Module.class).annotatedWith(red).toProvider(Providers.<Module>of(null));
           bind(Provider.class).annotatedWith(red).toProvider(Providers.<Provider>of(null));
           bind(Scope.class).annotatedWith(red).toProvider(Providers.<Scope>of(null));
+          bind(Stage.class).annotatedWith(red).toProvider(Providers.<Stage>of(null));
           bind(TypeLiteral.class).annotatedWith(red).toProvider(Providers.<TypeLiteral>of(null));
           bind(new TypeLiteral<Key<String>>() {}).toProvider(Providers.<Key<String>>of(null));
         }
@@ -471,6 +472,7 @@
           "Binding to core guice framework type is not allowed: Module.",
           "Binding to Provider is not allowed.",
           "Binding to core guice framework type is not allowed: Scope.",
+          "Binding to core guice framework type is not allowed: Stage.",
           "Binding to core guice framework type is not allowed: TypeLiteral.",
           "Binding to core guice framework type is not allowed: Key.");
     }
diff --git a/core/test/com/google/inject/BindingTest.java b/core/test/com/google/inject/BindingTest.java
index 46359d5..df91c44 100644
--- a/core/test/com/google/inject/BindingTest.java
+++ b/core/test/com/google/inject/BindingTest.java
@@ -370,8 +370,7 @@
       }
     });
     
-    assertEquals(ImmutableSet.of(TypeLiteral.get(Stage.class), TypeLiteral.get(D.class)),
-        heardTypes);
+    assertEquals(ImmutableSet.of(TypeLiteral.get(D.class)), heardTypes);
   }
 
   public void testInterfaceToImplementationConstructor() throws NoSuchMethodException {
diff --git a/core/test/com/google/inject/ProvisionListenerTest.java b/core/test/com/google/inject/ProvisionListenerTest.java
index 421cb89..860910a 100644
--- a/core/test/com/google/inject/ProvisionListenerTest.java
+++ b/core/test/com/google/inject/ProvisionListenerTest.java
@@ -21,17 +21,21 @@
 import static com.google.inject.name.Names.named;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.inject.matcher.AbstractMatcher;
 import com.google.inject.matcher.Matcher;
 import com.google.inject.matcher.Matchers;
 import com.google.inject.name.Named;
 import com.google.inject.spi.DependencyAndSource;
+import com.google.inject.spi.InstanceBinding;
 import com.google.inject.spi.ProvisionListener;
+import com.google.inject.util.Providers;
 
 import junit.framework.TestCase;
 
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -244,6 +248,8 @@
           throw new RuntimeException(ex);
         }
         bind(LinkedFoo.class).to(Foo.class);
+        bind(Interface.class).toInstance(new Implementation());
+        bindConstant().annotatedWith(named("constant")).to("MyConstant");
       }
       
       @Provides @Named("pi") Foo provideFooBar() {
@@ -251,6 +257,11 @@
       }
     });
     
+    // toInstance & constant bindings are notified in random order, at the very beginning.
+    assertEquals(
+        ImmutableSet.of(Key.get(Interface.class), Key.get(String.class, named("constant"))),
+        capturer.getAsSetAndClear());
+    
     // simple binding
     assertNotNull(injector.getInstance(Foo.class));
     assertEquals(of(Key.get(Foo.class)), capturer.getAndClear());
@@ -334,6 +345,9 @@
     }
   }
   
+  interface Interface {}
+  class Implementation implements Interface {}
+  
   @Singleton static class Sole {}
   static class Many {}
   
@@ -370,8 +384,24 @@
     public <T> void onProvision(ProvisionInvocation<T> provision) {
       keys.add(provision.getBinding().getKey());
       T provisioned = provision.provision();
+      // InstanceBindings are the only kind of binding where the key can
+      // be an instanceof the provisioned, because it isn't linked to any
+      // direct implementation.  I guess maybe it'd also be possible
+      // with a toConstructor binding... but we don't use that in our tests.
+      if (provision.getBinding() instanceof InstanceBinding) {
+        Class<? super T> expected = provision.getBinding().getKey().getRawType();
+        assertTrue("expected instanceof: " + expected + ", but was: " + provisioned,
+            expected.isInstance(provisioned));
+      } else {
       assertEquals(provision.getBinding().getKey().getRawType(), provisioned.getClass());
     }
+    }
+    
+    Set<Key> getAsSetAndClear() {
+      Set<Key> copy = ImmutableSet.copyOf(keys);
+      keys.clear();
+      return copy;
+    }
     
     List<Key> getAndClear() {
       List<Key> copy = ImmutableList.copyOf(keys);
@@ -454,8 +484,10 @@
         
         // Build up a list of asserters for our dependency chains.
         ImmutableList.Builder<Class<?>> chain = ImmutableList.builder();
+        chain.add(Instance.class);
+        bindListener(keyMatcher(Instance.class), new ChainAsserter(pList, chain.build()));
         
-        chain.add(Instance.class).add(A.class);
+        chain.add(A.class);
         bindListener(keyMatcher(A.class), new ChainAsserter(pList, chain.build()));
         
         chain.add(B.class).add(BImpl.class);
@@ -482,7 +514,8 @@
     });
     Instance instance = injector.getInstance(Instance.class);
     // make sure we're checking all of the chain asserters..
-    assertEquals(of(A.class, BImpl.class, C.class, DP.class, D.class, E.class, F.class),
+    assertEquals(
+        of(Instance.class, A.class, BImpl.class, C.class, DP.class, D.class, E.class, F.class),
         pList);
     // and make sure that nothing else was notified that we didn't expect.
     assertEquals(totalList, pList);
@@ -585,5 +618,22 @@
     @SuppressWarnings("unused")
     @Inject F f;
   }
-  private static class F {}
+  private static class F {
+  }
+
+  public void testBindToInjectorWithListeningGivesSaneException() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        @Override
+        protected void configure() {
+          bindListener(Matchers.any(), new Counter());
+          bind(Injector.class).toProvider(Providers.<Injector>of(null));
+        }
+      });
+      fail();
+    } catch (CreationException ce) {
+      assertContains(
+          ce.getMessage(), "Binding to core guice framework type is not allowed: Injector.");
+    }
+  }
 }
diff --git a/core/test/com/google/inject/TypeListenerTest.java b/core/test/com/google/inject/TypeListenerTest.java
index 5526d2e..549bb91 100644
--- a/core/test/com/google/inject/TypeListenerTest.java
+++ b/core/test/com/google/inject/TypeListenerTest.java
@@ -596,7 +596,8 @@
     try {
       Guice.createInjector(new AbstractModule() {
         protected void configure() {
-          bindListener(Matchers.only(new TypeLiteral<Stage>() {}), new TypeListener() {
+          requestInjection(new Object());
+          bindListener(Matchers.any(), new TypeListener() {
             public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
               encounter.addError("There was an error on %s", type);
               encounter.addError(new IllegalArgumentException("whoops!"));
@@ -609,7 +610,7 @@
       fail();
     } catch (CreationException expected) {
       assertContains(expected.getMessage(),
-          "1) There was an error on com.google.inject.Stage",
+          "1) There was an error on java.lang.Object",
           "2) An exception was caught and reported. Message: whoops!",
           "3) And another problem",
           "4) An exception was caught and reported. Message: null",
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java b/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
index 11738e6..eb43eaf 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
@@ -500,7 +500,7 @@
     return new MapResult<K, V>(k, new BindResult<V>(PROVIDER_INSTANCE, v, null));
   }
 
-  private static class MapResult<K, V> {
+  static class MapResult<K, V> {
     private final K k;
     private final BindResult<V> v;
     
@@ -534,7 +534,7 @@
   /** The kind of binding. */
   static enum BindType { INSTANCE, LINKED, PROVIDER_INSTANCE }
   /** The result of the binding. */
-  private static class BindResult<T> {
+  static class BindResult<T> {
     private final BindType type;
     private final Key<? extends T> key;
     private final T instance;