Extended Binding to better support tools. Fixed bug where we were ignoring exceptions during member injection. Added TOOL stage.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@354 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/BinderImpl.java b/src/com/google/inject/BinderImpl.java
index 8710414..28cdfc6 100644
--- a/src/com/google/inject/BinderImpl.java
+++ b/src/com/google/inject/BinderImpl.java
@@ -23,6 +23,7 @@
 import static com.google.inject.internal.Objects.nonNull;
 import com.google.inject.internal.StackTraceElements;
 import com.google.inject.internal.Stopwatch;
+import com.google.inject.internal.Objects;
 import com.google.inject.matcher.Matcher;
 import com.google.inject.spi.Message;
 import com.google.inject.spi.SourceProviders;
@@ -134,13 +135,30 @@
 
   final List<CreationListener> creationListeners
       = new ArrayList<CreationListener>();
-  final List<CreationListener> instanceInjectors
-      = new ArrayList<CreationListener>();
 
   interface CreationListener {
     void notify(InjectorImpl injector);
   }
 
+  final List<MembersInjector> membersInjectors = new ArrayList<MembersInjector>();
+
+  static class MembersInjector {
+
+    final Object o;
+
+    MembersInjector(Object o) {
+      this.o = o;
+    }
+
+    void checkDependencies(InjectorImpl injector) {
+      injector.injectors.get(o.getClass());
+    }
+
+    void injectMembers(InjectorImpl injector) {
+      injector.injectMembers(o);
+    }    
+  }
+
   public void bindInterceptor(Matcher<? super Class<?>> classMatcher,
       Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors) {
     proxyFactoryBuilder.intercept(classMatcher, methodMatcher, interceptors);
@@ -242,9 +260,10 @@
    * @throws IllegalStateException if called more than once
    */
   Injector createInjector() throws CreationException {
-    stopwatch.resetAndLog(logger, "Configuration");
+    stopwatch.resetAndLog(logger, "Configuration (running the modules)");
 
-    Map<Key<?>, BindingImpl<?>> bindings = new HashMap<Key<?>, BindingImpl<?>>();
+    Map<Key<?>, BindingImpl<?>> bindings
+        = new HashMap<Key<?>, BindingImpl<?>>();
     injector = new InjectorImpl(
         proxyFactoryBuilder.create(), bindings, scopes);
     injector.setErrorHandler(configurationErrorHandler);
@@ -275,6 +294,12 @@
 
     stopwatch.resetAndLog(logger, "Static validation");
 
+    for (MembersInjector membersInjector : membersInjectors) {
+      membersInjector.checkDependencies(injector);
+    }
+
+    stopwatch.resetAndLog(logger, "Instance member validation");
+
     // Blow up if we encountered errors.
     if (!errorMessages.isEmpty()) {
       throw new CreationException(errorMessages);
@@ -283,6 +308,13 @@
     // Switch to runtime error handling.
     injector.setErrorHandler(new RuntimeErrorHandler());
 
+    // If we're in the tool stage, stop here. Don't eagerly inject or load
+    // anything.
+    if (stage == Stage.TOOL) {
+      // TODO: Wrap this and prevent usage of anything besides getBindings().
+      return injector;
+    }
+
     // Inject static members.
     for (StaticInjection staticInjection : staticInjections) {
       staticInjection.runMemberInjectors(injector);
@@ -291,8 +323,8 @@
     stopwatch.resetAndLog(logger, "Static member injection");
 
     // Inject pre-existing instances.
-    for (CreationListener instanceInjector : instanceInjectors) {
-      instanceInjector.notify(injector);
+    for (MembersInjector membersInjector : membersInjectors) {
+      membersInjector.injectMembers(injector);
     }
 
     stopwatch.resetAndLog(logger, "Instance injection");
@@ -325,11 +357,7 @@
 
   private <T> void createBinding(BindingBuilderImpl<T> builder,
       List<ContextualCallable<Void>> preloaders) {
-    final Key<T> key = builder.getKey();
-    final InternalFactory<? extends T> factory
-        = builder.getInternalFactory(injector);
-    BindingImpl<?> binding
-        = BindingImpl.newInstance(injector, key, builder.getSource(), factory);
+    BindingImpl<T> binding = builder.build(injector);
 
     putBinding(binding);
 
@@ -337,7 +365,8 @@
     boolean preload = stage == Stage.PRODUCTION;
     if (builder.isSingletonScoped()) {
       if (preload || builder.shouldPreload()) {
-        preloaders.add(new BindingPreloader(key, factory));
+        preloaders.add(
+            new BindingPreloader(binding.key, binding.internalFactory));
       }
     }
     else {
@@ -478,7 +507,7 @@
 
     public BindingPreloader(Key<?> key, InternalFactory<?> factory) {
       this.key = key;
-      this.factory = factory;
+      this.factory = Objects.nonNull(factory, "factory");
     }
 
     public Void call(InternalContext context) {
diff --git a/src/com/google/inject/Binding.java b/src/com/google/inject/Binding.java
index 23bdba3..5dcd6f3 100644
--- a/src/com/google/inject/Binding.java
+++ b/src/com/google/inject/Binding.java
@@ -16,6 +16,8 @@
 
 package com.google.inject;
 
+import com.google.inject.spi.BindingVisitor;
+
 /**
  * A mapping from a key (type and optional annotation) to a provider of
  * instances of that type.  This interface is part of the {@link Injector}
@@ -34,11 +36,29 @@
    * Returns an arbitrary object containing information about the "place"
    * where this binding was configured. Used by Guice in the production of
    * descriptive error messages.
+   *
+   * <p>Tools might specially handle types they know about;
+   * {@code StackTraceElement} is a good example. Tools should simply call
+   * {@code toString()} on the source object if the type is unfamiliar.
    */
   Object getSource();
 
   /**
-   * Returns the provider guice uses to fulfill requests for this binding.
+   * Returns the scoped provider guice uses to fulfill requests for this
+   * binding.
    */
   Provider<T> getProvider();
+
+  /**
+   * Returns the scope applied by this binding.
+   */
+  Scope getScope();
+
+  /**
+   * Accepts a binding visitor. Invokes the visitor method specific to this
+   * binding's type.
+   *
+   * @param visitor to call back on
+   */
+  void accept(BindingVisitor<? super T> visitor);
 }
diff --git a/src/com/google/inject/BindingBuilderImpl.java b/src/com/google/inject/BindingBuilderImpl.java
index c11cb02..b959be8 100644
--- a/src/com/google/inject/BindingBuilderImpl.java
+++ b/src/com/google/inject/BindingBuilderImpl.java
@@ -17,14 +17,21 @@
 package com.google.inject;
 
 import com.google.inject.BinderImpl.CreationListener;
+import com.google.inject.BinderImpl.MembersInjector;
 import com.google.inject.binder.AnnotatedBindingBuilder;
 import com.google.inject.binder.ScopedBindingBuilder;
 import com.google.inject.internal.Annotations;
 import com.google.inject.internal.Objects;
 import com.google.inject.internal.StackTraceElements;
 import com.google.inject.internal.ToStringBuilder;
+import com.google.inject.internal.Classes;
+import com.google.inject.spi.BindingVisitor;
+import com.google.inject.spi.InstanceBinding;
+import com.google.inject.spi.LinkedBinding;
+import com.google.inject.spi.ProviderInstanceBinding;
+import com.google.inject.spi.ProviderBinding;
+import com.google.inject.spi.ClassBinding;
 import java.lang.annotation.Annotation;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
@@ -38,11 +45,17 @@
   final Object source;
   Key<T> key;
   InternalFactory<? extends T> factory;
-  T instance;
   Scope scope;
   boolean preload = false;
   private BinderImpl binder;
 
+  // These fields keep track of the raw implementation for later use in the
+  // Binding API.
+  T instance;
+  Key<? extends T> targetKey;
+  Provider<? extends T> providerInstance;
+  Key<? extends Provider<? extends T>> providerKey;
+
   BindingBuilderImpl(BinderImpl binder, Key<T> key, Object source) {
     this.binder = binder;
     this.key = Objects.nonNull(key, "key");
@@ -129,6 +142,7 @@
         new FactoryProxy<T>(key, targetKey, source);
     this.factory = factoryProxy;
     binder.creationListeners.add(factoryProxy);
+    this.targetKey = targetKey;
     return this;
   }
 
@@ -137,6 +151,8 @@
     this.instance = instance;
     this.factory = new ConstantFactory<T>(instance, source);
     registerInstanceForInjection(instance);
+
+    // TODO: I don't think this can happen anymore.
     if (this.scope != null) {
       binder.addError(source, ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
     }
@@ -154,6 +170,7 @@
   public ScopedBindingBuilder toProvider(Provider<? extends T> provider) {
     ensureImplementationIsNotSet();
     this.factory = new InternalFactoryToProviderAdapter<T>(provider, source);
+    this.providerInstance = provider;
     registerInstanceForInjection(provider);
     return this;
   }
@@ -171,6 +188,7 @@
         new BoundProviderFactory<T>(providerKey, source);
     binder.creationListeners.add(boundProviderFactory);
     this.factory = boundProviderFactory;
+    this.providerKey = providerKey;
 
     return this;
   }
@@ -224,9 +242,63 @@
     return preload;
   }
 
-  InternalFactory<? extends T> getInternalFactory(InjectorImpl injector) {
-    if (this.factory == null && !key.hasAnnotationType()) {
-      // Try an implicit binding.
+  BindingImpl<T> build(InjectorImpl injector) {
+    if (this.factory != null) {
+      Scope scope = this.scope == null ? Scopes.NO_SCOPE : this.scope;
+
+      InternalFactory<? extends T> scopedFactory
+          = Scopes.scope(this.key, injector, this.factory, scope);
+
+      // Instance binding.
+      if (instance != null) {
+        return new InstanceBindingImpl<T>(
+            injector, key, source, scopedFactory, instance);
+      }
+
+      // Linked binding.
+      if (this.targetKey != null) {
+        return new LinkedBindingImpl<T>(
+            injector, key, source, scopedFactory, scope, targetKey);
+      }
+
+      // Provider instance binding.
+      if (this.providerInstance != null) {
+        return new ProviderInstanceBindingImpl<T>(
+            injector, key, source, scopedFactory, scope, providerInstance);
+      }
+
+      // Provider binding.
+      if (this.providerKey != null) {
+        return new ProviderBindingImpl<T>(
+            injector, key, source, scopedFactory, scope, providerKey);
+      }
+
+      // Unknown binding type. We just have a raw internal factory.
+      // This happens with the Injector binding, for example.
+      return new UnknownBindingImpl<T>(injector, key, source, scopedFactory);
+
+    } else {
+      // If we're here, the type we bound to is also the implementation.
+      // Example: bind(FooImpl.class).in(Scopes.SINGLETON);
+
+      Class<?> rawType = key.getRawType();
+
+      // Error: Inner class.
+      if (Classes.isInnerClass(rawType)) {
+        injector.errorHandler.handle(source,
+            ErrorMessages.CANNOT_INJECT_INNER_CLASS, rawType);
+        return invalidBinding(injector);
+      }
+
+      // Error: Missing implementation.
+      // Example: bind(Runnable.class);
+      // Example: bind(Date.class).annotatedWith(Red.class);
+      if (key.hasAnnotationType() || !Classes.isConcrete(rawType)) {
+        injector.errorHandler.handle(source,
+            ErrorMessages.MISSING_IMPLEMENTATION);
+        return invalidBinding(injector);
+      }
+
       final ImplicitImplementation<T> implicitImplementation =
           new ImplicitImplementation<T>(key, scope, source);
       binder.creationListeners.add(implicitImplementation);
@@ -237,12 +309,201 @@
         // recorded.
         this.scope = Scopes.getScopeForType(
             key.getTypeLiteral().getRawType(), binder.scopes, IGNORE_ERRORS);
+
+        if (this.scope == null) {
+          this.scope = Scopes.NO_SCOPE;
+        }
       }
 
-      return implicitImplementation;
+      return new ClassBindingImpl<T>(injector, key, source,
+          implicitImplementation, scope);
+    }
+  }
+
+  InvalidBinding<T> invalidBinding(InjectorImpl injector) {
+    return new InvalidBinding<T>(injector, key, source);
+  }
+
+  private static class InvalidBinding<T> extends BindingImpl<T> {
+
+    InvalidBinding(InjectorImpl injector, Key<T> key, Object source) {
+      super(injector, key, source, new InternalFactory<T>() {
+        public T get(InternalContext context) {
+          throw new AssertionError();
+        }
+      }, Scopes.NO_SCOPE);
     }
 
-    return Scopes.scope(this.key, injector, this.factory, scope);
+    public void accept(BindingVisitor<? super T> bindingVisitor) {
+      throw new AssertionError();
+    }
+
+    public String toString() {
+      return "InvalidBinding";
+    }
+  }
+
+  private static class ClassBindingImpl<T> extends BindingImpl<T>
+      implements ClassBinding<T> {
+
+    ClassBindingImpl(InjectorImpl injector, Key<T> key, Object source,
+        InternalFactory<? extends T> internalFactory, Scope scope) {
+      super(injector, key, source, internalFactory, scope);
+    }
+
+    public void accept(BindingVisitor<? super T> visitor) {
+      visitor.visit(this);
+    }
+
+    @SuppressWarnings("unchecked")
+    public Class<T> getBoundClass() {
+      // T should always be the class itself.
+      return (Class<T>) key.getRawType();
+    }
+
+    @Override
+    public String toString() {
+      return new ToStringBuilder(ClassBinding.class)
+          .add("class", getBoundClass())
+          .add("scope", scope)
+          .add("source", source)
+          .toString();
+    }
+  }
+
+  private static class UnknownBindingImpl<T> extends BindingImpl<T> {
+
+    UnknownBindingImpl(InjectorImpl injector, Key<T> key, Object source,
+        InternalFactory<? extends T> internalFactory) {
+      super(injector, key, source, internalFactory, Scopes.NO_SCOPE);
+    }
+
+    public void accept(BindingVisitor<? super T> bindingVisitor) {
+      bindingVisitor.visitUnknown(this);
+    }
+  }
+
+  private static class InstanceBindingImpl<T> extends BindingImpl<T>
+      implements InstanceBinding<T> {
+
+    final T instance;
+
+    InstanceBindingImpl(InjectorImpl injector, Key<T> key, Object source,
+        InternalFactory<? extends T> internalFactory, T instance) {
+      super(injector, key, source, internalFactory, Scopes.NO_SCOPE);
+      this.instance = instance;
+    }
+
+    public void accept(BindingVisitor<? super T> bindingVisitor) {
+      bindingVisitor.visit(this);
+    }
+
+    public T getInstance() {
+      return this.instance;
+    }
+
+    @Override
+    public String toString() {
+      return new ToStringBuilder(InstanceBinding.class)
+          .add("key", key)
+          .add("instance", instance)
+          .add("source", source)
+          .toString();
+    }
+  }
+
+  private static class LinkedBindingImpl<T> extends BindingImpl<T>
+      implements LinkedBinding<T> {
+
+    final Key<? extends T> targetKey;
+
+    LinkedBindingImpl(InjectorImpl injector, Key<T> key, Object source,
+        InternalFactory<? extends T> internalFactory, Scope scope,
+        Key<? extends T> targetKey) {
+      super(injector, key, source, internalFactory, scope);
+      this.targetKey = targetKey;
+    }
+
+    public void accept(BindingVisitor<? super T> bindingVisitor) {
+      bindingVisitor.visit(this);
+    }
+
+    public Binding<? extends T> getTarget() {
+      return injector.getBinding(targetKey);
+    }
+
+    @Override
+    public String toString() {
+      return new ToStringBuilder(LinkedBinding.class)
+          .add("key", key)
+          .add("target", targetKey)
+          .add("scope", scope)
+          .add("source", source)
+          .toString();
+    }
+  }
+
+  private static class ProviderInstanceBindingImpl<T> extends BindingImpl<T>
+      implements ProviderInstanceBinding<T> {
+
+    final Provider<? extends T> providerInstance;
+
+    ProviderInstanceBindingImpl(InjectorImpl injector, Key<T> key,
+        Object source,
+        InternalFactory<? extends T> internalFactory, Scope scope,
+        Provider<? extends T> providerInstance) {
+      super(injector, key, source, internalFactory, scope);
+      this.providerInstance = providerInstance;
+    }
+
+    public void accept(BindingVisitor<? super T> bindingVisitor) {
+      bindingVisitor.visit(this);
+    }
+
+    public Provider<? extends T> getProviderInstance() {
+      return this.providerInstance;
+    }
+
+    @Override
+    public String toString() {
+      return new ToStringBuilder(ProviderInstanceBinding.class)
+          .add("key", key)
+          .add("provider", providerInstance)
+          .add("scope", scope)
+          .add("source", source)
+          .toString();
+    }
+  }
+
+  private static class ProviderBindingImpl<T> extends BindingImpl<T>
+      implements ProviderBinding<T> {
+
+    final Key<? extends Provider<? extends T>> providerKey;
+
+    ProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source,
+        InternalFactory<? extends T> internalFactory, Scope scope,
+        Key<? extends Provider<? extends T>> providerKey) {
+      super(injector, key, source, internalFactory, scope);
+      this.providerKey = providerKey;
+    }
+
+    public void accept(BindingVisitor<? super T> bindingVisitor) {
+      bindingVisitor.visit(this);
+    }
+
+    public Binding<? extends Provider<? extends T>> getProviderBinding() {
+      return injector.getBinding(providerKey);
+    }
+
+    @Override
+    public String toString() {
+      return new ToStringBuilder(ProviderBinding.class)
+          .add("key", key)
+          .add("provider", providerKey)
+          .add("scope", scope)
+          .add("source", source)
+          .toString();
+    }
   }
 
   boolean isSingletonScoped() {
@@ -250,22 +511,7 @@
   }
 
   void registerInstanceForInjection(final Object o) {
-    binder.instanceInjectors.add(new CreationListener() {
-      public void notify(InjectorImpl injector) {
-        try {
-          injector.injectMembers(o);
-        }
-        catch (Exception e) {
-          String className = e.getClass().getSimpleName();
-          String message = ErrorMessages.getRootMessage(e);
-          String logMessage = String.format(
-              ErrorMessages.ERROR_INJECTING_MEMBERS, o, message);
-          logger.log(Level.INFO, logMessage, e);
-          binder.addError(source, ErrorMessages.ERROR_INJECTING_MEMBERS_SEE_LOG,
-              className, o, message);
-        }
-      }
-    });
+    binder.membersInjectors.add(new MembersInjector(o));
   }
 
   /**
diff --git a/src/com/google/inject/BindingImpl.java b/src/com/google/inject/BindingImpl.java
index 02e794c..2868a33 100644
--- a/src/com/google/inject/BindingImpl.java
+++ b/src/com/google/inject/BindingImpl.java
@@ -21,19 +21,21 @@
 /**
  * @author crazybob@google.com (Bob Lee)
  */
-class BindingImpl<T> implements Binding<T> {
+abstract class BindingImpl<T> implements Binding<T> {
 
   final InjectorImpl injector;
   final Key<T> key;
   final Object source;
   final InternalFactory<? extends T> internalFactory;
+  final Scope scope;
 
   BindingImpl(InjectorImpl injector, Key<T> key, Object source,
-      InternalFactory<? extends T> internalFactory) {
+      InternalFactory<? extends T> internalFactory, Scope scope) {
     this.injector = injector;
     this.key = key;
     this.source = source;
     this.internalFactory = internalFactory;
+    this.scope = scope;
   }
 
   public Key<T> getKey() {
@@ -57,9 +59,8 @@
     return internalFactory;
   }
 
-  static <T> BindingImpl<T> newInstance(InjectorImpl injector, Key<T> key,
-      Object source, InternalFactory<? extends T> internalFactory) {
-    return new BindingImpl<T>(injector, key, source, internalFactory);
+  public Scope getScope() {
+    return this.scope;
   }
 
   /**
@@ -70,10 +71,11 @@
   }
 
   public String toString() {
-    return new ToStringBuilder(BindingImpl.class)
+    return new ToStringBuilder(Binding.class)
         .add("key", key)
-        .add("source", source)
         .add("provider", internalFactory)
+        .add("scope", scope)
+        .add("source", source)
         .toString();
   }
 }
\ No newline at end of file
diff --git a/src/com/google/inject/ConstantBindingBuilderImpl.java b/src/com/google/inject/ConstantBindingBuilderImpl.java
index f1c51d7..4089319 100644
--- a/src/com/google/inject/ConstantBindingBuilderImpl.java
+++ b/src/com/google/inject/ConstantBindingBuilderImpl.java
@@ -22,6 +22,9 @@
 import com.google.inject.internal.Annotations;
 import com.google.inject.internal.Objects;
 import com.google.inject.internal.StackTraceElements;
+import com.google.inject.internal.ToStringBuilder;
+import com.google.inject.spi.BindingVisitor;
+import com.google.inject.spi.ConstantBinding;
 import java.lang.annotation.Annotation;
 
 /**
@@ -158,7 +161,36 @@
     BindingImpl<T> createBinding(InjectorImpl injector) {
       Key<T> key = Key.get(type, annotationStrategy);
       ConstantFactory<T> factory = new ConstantFactory<T>(value, source);
-      return BindingImpl.newInstance(injector, key, source, factory);
+      return new ContantBindingImpl<T>(injector, key, source, factory, value);
+    }
+  }
+
+  private static class ContantBindingImpl<T> extends BindingImpl<T>
+      implements ConstantBinding<T> {
+
+    final T value;
+
+    ContantBindingImpl(InjectorImpl injector, Key<T> key, Object source,
+        InternalFactory<T> internalFactory, T value) {
+      super(injector, key, source, internalFactory, Scopes.NO_SCOPE);
+      this.value = value;
+    }
+
+    public void accept(BindingVisitor<? super T> bindingVisitor) {
+      bindingVisitor.visit(this);
+    }
+
+    public T getValue() {
+      return this.value;
+    }
+
+    @Override
+    public String toString() {
+      return new ToStringBuilder(ConstantBinding.class)
+          .add("key", key)
+          .add("value", value)
+          .add("source", source)
+          .toString();
     }
   }
 }
diff --git a/src/com/google/inject/ConstructorInjector.java b/src/com/google/inject/ConstructorInjector.java
index f1e0cb7..35c0757 100644
--- a/src/com/google/inject/ConstructorInjector.java
+++ b/src/com/google/inject/ConstructorInjector.java
@@ -68,7 +68,7 @@
     }
   }
 
-  private Constructor<T> findConstructorIn(InjectorImpl injector,
+  private static <T> Constructor<T> findConstructorIn(InjectorImpl injector,
       Class<T> implementation) {
     Constructor<T> found = null;
     @SuppressWarnings("unchecked")
diff --git a/src/com/google/inject/ErrorMessages.java b/src/com/google/inject/ErrorMessages.java
index 9b8e641..5e10735 100644
--- a/src/com/google/inject/ErrorMessages.java
+++ b/src/com/google/inject/ErrorMessages.java
@@ -70,9 +70,6 @@
   static final String RECURSIVE_PROVIDER_TYPE = "@DefaultProvider"
       + " points to the same class it annotates.";
 
-  static final String ERROR_INJECTING_MEMBERS = "An error occurred"
-      + " while injecting members of %s. Error message: %s";
-
   static final String ERROR_INJECTING_MEMBERS_SEE_LOG = "An error of type %s"
       + " occurred while injecting members of %s. See log for details. Error"
       + " message: %s";
@@ -83,6 +80,9 @@
   static final String EXCEPTION_REPORTED_BY_MODULE_SEE_LOG = "An exception"
       + " was caught and reported. See log for details. Message: %s";
 
+  static final String MISSING_IMPLEMENTATION
+      = "No implementation was specified.";
+
   static final String MISSING_BINDING_ANNOTATION = "Please annotate with"
       + " @BindingAnnotation. Bound at %s.";
 
@@ -156,23 +156,28 @@
       + " singleton-scoped bindings.";
 
   static final String ERROR_INJECTING_FIELD = "Error injecting field";
+
   static final String ERROR_INJECTING_METHOD = "Error injecting method";
+
   static final String ERROR_INJECTING_CONSTRUCTOR =
       "Error injecting constructor";
+
   static final String ERROR_IN_PROVIDER = "Error in custom provider";
 
   static final String ERROR_WHILE_LOCATING_FIELD =
       "  while locating %s%n    for field at %s";
+
   static final String ERROR_WHILE_LOCATING_PARAMETER =
       "  while locating %s%n    for parameter %s at %s";
+
   static final String ERROR_WHILE_LOCATING_VALUE =
       "  while locating %s";
+
   static final String CANNOT_INJECT_NULL =
       "null returned by binding at %s";
+
   static final String CANNOT_INJECT_NULL_INTO_MEMBER =
-      "null returned by binding at %s%n    but %s is not @Nullable";
-
-
+      "null returned by binding at %s%n but %s is not @Nullable";
 
   static String getRootMessage(Throwable t) {
     Throwable cause = t.getCause();
diff --git a/src/com/google/inject/Injector.java b/src/com/google/inject/Injector.java
index 2e4a480..ee07f4c 100644
--- a/src/com/google/inject/Injector.java
+++ b/src/com/google/inject/Injector.java
@@ -16,7 +16,6 @@
 
 package com.google.inject;
 
-import com.google.inject.introspect.Resolver;
 import java.util.List;
 import java.util.Map;
 
@@ -66,10 +65,8 @@
 
   /**
    * Gets a binding for the given key, or null if no binding for this key is
-   * found.  Note that if this key references an implementation class that can
-   * be implicitly bound, this method may return null, but may later return the
-   * implicit binding after it has been loaded. This method is part of the
-   * Injector Introspection API and is primarily intended for use by tools.
+   * found. This method is part of the Injector Introspection API and is
+   * primarily intended for use by tools.
    */
   <T> Binding<T> getBinding(Key<T> key);
 
@@ -108,11 +105,4 @@
    * dependencies ahead of time.
    */
   <T> T getInstance(Class<T> type);
-
-  /**
-   * Returns the resolver used by this injector to resolve injection requests.
-   * This method is part of the Injector Introspection API and is primarily
-   * intended for use by tools.
-   */
-  Resolver getResolver();
 }
diff --git a/src/com/google/inject/InjectorImpl.java b/src/com/google/inject/InjectorImpl.java
index 903e280..eac24a9 100644
--- a/src/com/google/inject/InjectorImpl.java
+++ b/src/com/google/inject/InjectorImpl.java
@@ -17,12 +17,11 @@
 package com.google.inject;
 
 import com.google.inject.internal.GuiceFastClass;
-import com.google.inject.internal.Objects;
 import com.google.inject.internal.ReferenceCache;
 import com.google.inject.internal.StackTraceElements;
 import com.google.inject.internal.Strings;
 import com.google.inject.internal.ToStringBuilder;
-import com.google.inject.introspect.Resolver;
+import com.google.inject.internal.Classes;
 import com.google.inject.spi.SourceProviders;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
@@ -407,6 +406,9 @@
 
   @SuppressWarnings("unchecked")
   public <T> BindingImpl<T> getBinding(Key<T> key) {
+    // TODO: Create binding objects for implicit bindings on the fly. This
+    // includes classes, Provider<X>, converted constants, etc.
+    
     return (BindingImpl<T>) bindings.get(key);
   }
 
@@ -602,12 +604,12 @@
       = new ReferenceCache<Class<?>, ConstructorInjector>() {
     @SuppressWarnings("unchecked")
     protected ConstructorInjector<?> create(Class<?> implementation) {
-      if (implementation.isInterface()) {
+      if (!Classes.isConcrete(implementation)) {
         errorHandler.handle(defaultSource,
             ErrorMessages.CANNOT_INJECT_ABSTRACT_TYPE, implementation);
         return ConstructorInjector.invalidConstructor();
       }
-      if (isInnerClass(implementation)) {
+      if (Classes.isInnerClass(implementation)) {
         errorHandler.handle(defaultSource,
             ErrorMessages.CANNOT_INJECT_INNER_CLASS, implementation);
         return ConstructorInjector.invalidConstructor();
@@ -617,11 +619,6 @@
     }
   };
 
-  private static boolean isInnerClass(Class<?> c) {
-    return c.getEnclosingClass() != null
-        && !Modifier.isStatic(c.getModifiers());
-  }
-
   /**
    * A placeholder. This enables us to continue processing and gather more
    * errors but blows up if you actually try to use it.
@@ -878,10 +875,6 @@
     }
   }
 
-  public Resolver getResolver() {
-    throw new UnsupportedOperationException();
-  }
-
   /**
    * Converts a {@code String} to another type.
    */
diff --git a/src/com/google/inject/ProviderMethods.java b/src/com/google/inject/ProviderMethods.java
index b3185be..20069e0 100644
--- a/src/com/google/inject/ProviderMethods.java
+++ b/src/com/google/inject/ProviderMethods.java
@@ -27,9 +27,9 @@
 import java.util.List;
 
 /**
- * Creates bindings to methods annotated with {@link
- * @com.google.inject.Provides}. Use the scope and binding annotations on the
- * provider method to configure the binding.
+ * Creates bindings to methods annotated with
+ * {@link com.google.inject.Provides}. Use the scope and binding annotations
+ * on the provider method to configure the binding.
  */
 public class ProviderMethods {
 
diff --git a/src/com/google/inject/ProviderMethodsTest.java b/src/com/google/inject/ProviderMethodsTest.java
deleted file mode 100644
index 108fab6..0000000
--- a/src/com/google/inject/ProviderMethodsTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * Copyright (C) 2007 Google Inc.
- *
- * 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 com.google.inject;
-
-import junit.framework.TestCase;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * @author crazybob@google.com (Bob Lee)
- */
-public class ProviderMethodsTest extends TestCase {
-
-  public void testProviderMethods() {
-    Injector injector = Guice.createInjector(new Module() {
-      public void configure(Binder binder) {
-        binder.install(ProviderMethods.from(ProviderMethodsTest.this));
-      }
-    });
-
-    Bob bob = injector.getInstance(Bob.class);
-    assertEquals("A Bob", bob.getName());
-
-    Bob clone = injector.getInstance(Bob.class);
-    assertEquals("A Bob", clone.getName());
-
-    assertNotSame(bob, clone);
-    assertSame(bob.getDaughter(), clone.getDaughter());
-
-    Key soleBobKey = Key.get(Bob.class, Sole.class);
-    assertSame(
-        injector.getInstance(soleBobKey),
-        injector.getInstance(soleBobKey)
-    );
-  }
-
-  interface Bob {
-    String getName();
-    Dagny getDaughter();
-  }
-
-  interface Dagny {
-    int getAge();
-  }
-
-  @Provides
-  Bob provideBob(final Dagny dagny) {
-    return new Bob() {
-      public String getName() {
-        return "A Bob";
-      }
-
-      public Dagny getDaughter() {
-        return dagny;
-      }
-    };
-  }
-
-  @Provides
-  @Singleton
-  @Sole
-  Bob provideSoleBob(final Dagny dagny) {
-    return new Bob() {
-      public String getName() {
-        return "Only Bob";
-      }
-
-      public Dagny getDaughter() {
-        return dagny;
-      }
-    };
-  }
-
-  @Provides
-  @Singleton
-  Dagny provideDagny() {
-    return new Dagny() {
-      public int getAge() {
-        return 1;
-      }
-    };
-  }
-
-  @Retention(RUNTIME)
-  @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
-  @BindingAnnotation
-  @interface Sole {}
-
-// We'll have to make getProvider() support circular dependencies before this
-// will work.
-//
-//  public void testCircularDependency() {
-//    Injector injector = Guice.createInjector(new Module() {
-//      public void configure(Binder binder) {
-//        binder.install(ProviderMethods.from(ProviderMethodsTest.this));
-//      }
-//    });
-//
-//    Foo foo = injector.getInstance(Foo.class);
-//    assertEquals(5, foo.getI());
-//    assertEquals(10, foo.getBar().getI());
-//    assertEquals(5, foo.getBar().getFoo().getI());
-//  }
-//
-//  interface Foo {
-//    Bar getBar();
-//    int getI();
-//  }
-//
-//  interface Bar {
-//    Foo getFoo();
-//    int getI();
-//  }
-//
-//  @Provides Foo newFoo(final Bar bar) {
-//    return new Foo() {
-//
-//      public Bar getBar() {
-//        return bar;
-//      }
-//
-//      public int getI() {
-//        return 5;
-//      }
-//    };
-//  }
-//
-//  @Provides Bar newBar(final Foo foo) {
-//    return new Bar() {
-//
-//      public Foo getFoo() {
-//        return foo;
-//      }
-//
-//      public int getI() {
-//        return 10;
-//      }
-//    };
-//  }
-}
\ No newline at end of file
diff --git a/src/com/google/inject/Scopes.java b/src/com/google/inject/Scopes.java
index 37d45fb..cc29a02 100644
--- a/src/com/google/inject/Scopes.java
+++ b/src/com/google/inject/Scopes.java
@@ -132,7 +132,7 @@
       InjectorImpl injector, InternalFactory<? extends T> creator,
       Scope scope) {
     // No scope does nothing.
-    if (scope == null) {
+    if (scope == null || scope == Scopes.NO_SCOPE) {
       return creator;
     }
     Provider<T> scoped = scope.scope(key,
diff --git a/src/com/google/inject/Stage.java b/src/com/google/inject/Stage.java
index 7b65a70..e13acb3 100644
--- a/src/com/google/inject/Stage.java
+++ b/src/com/google/inject/Stage.java
@@ -24,8 +24,16 @@
 public enum Stage {
 
   /**
-   * We want fast startup times and better error reporting at the expense of
-   * runtime performance and some up front error checking.
+   * We're running in a tool (an IDE plugin for example). We need binding
+   * meta data but not a functioning Injector. Do not inject members of
+   * instances. Do not load eager singletons. Do as little as possible so
+   * our tools run nice and snappy.
+   */
+  TOOL,
+
+  /**
+   * The default stage. We want fast startup times and better error reporting
+   * at the expense of runtime performance and some up front error checking.
    */
   DEVELOPMENT,
 
diff --git a/src/com/google/inject/internal/Classes.java b/src/com/google/inject/internal/Classes.java
new file mode 100644
index 0000000..1b1b52f
--- /dev/null
+++ b/src/com/google/inject/internal/Classes.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.internal;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Class utilities.
+ */
+public class Classes {
+
+  public static boolean isInnerClass(Class<?> clazz) {
+    return clazz.getEnclosingClass() != null
+        && !Modifier.isStatic(clazz.getModifiers());
+  }
+
+  public static boolean isConcrete(Class<?> clazz) {
+    int modifiers = clazz.getModifiers();
+    return !clazz.isInterface() && !Modifier.isAbstract(modifiers);
+  }
+}
diff --git a/src/com/google/inject/introspect/Dependency.java b/src/com/google/inject/introspect/Dependency.java
deleted file mode 100644
index 7d982cb..0000000
--- a/src/com/google/inject/introspect/Dependency.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.google.inject.introspect;
-
-import com.google.inject.Key;
-
-/**
- * Javadoc.
- *
- * @author Kevin Bourrillion (kevinb9n@gmail.com)
- */
-public interface Dependency<T> {
-
-  Implementation<?> getDependent();
-
-  Key<T> getKey();
-
-  boolean usesProviderInjection();
-
-  InjectionStyle getInjectionStyle();
-
-  // put this enum somewhere else?
-  enum InjectionStyle { FIELD, METHOD, CONSTRUCTOR }
-}
diff --git a/src/com/google/inject/introspect/Implementation.java b/src/com/google/inject/introspect/Implementation.java
deleted file mode 100644
index 9a157e8..0000000
--- a/src/com/google/inject/introspect/Implementation.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.google.inject.introspect;
-
-import com.google.inject.Key;
-import com.google.inject.Provider;
-import com.google.inject.Scope;
-import java.lang.reflect.Constructor;
-import java.util.Set;
-
-/**
- * Javadoc.
- *
- * @author Kevin Bourrillion (kevinb9n@gmail.com)
- */
-public interface Implementation<T> {
-
-  enum ProvisionStrategy {
-
-    /**
-     * An instance was provided to Guice by the Module; this instance will be
-     * used to fulfill every request.
-     */
-    INSTANCE,
-
-    /**
-     * Guice obtains instances for this implementation by invoking an injectable
-     * constructor (either the lone constructor marked with {@code @Inject} or
-     * a parameterless constructor).
-     */
-    CONSTRUCTOR,
-
-    /**
-     * Guice will resolve a Provider key to an instance, then use this provider
-     * instance to provide the current implementation.
-     */
-    PROVIDER,
-
-    /**
-     * This is a reserved key that Guice provides natively, like Injector or
-     * Stage.
-     */
-    RESERVED,
-  }
-
-  /**
-   * Returns the strategy Guice will use to provide instances for this
-   * implementation.
-   */
-  ProvisionStrategy getProvisionStrategy();
-
-  /**
-   * Returns the constructor Guice will use to obtain instances for this
-   * implementation.
-   *
-   * @throws IllegalStateException if {@link #getProvisionStrategy()} is not
-   *     {@link ProvisionStrategy#CONSTRUCTOR}.
-   */
-  Constructor<? extends T> getInjectableConstructor();
-
-  /**
-   * Returns the provider Guice will use to obtain instances for this
-   * implementation.  TODO: what about @Provides methods?
-   *
-   * @throws IllegalStateException if {@link #getProvisionStrategy()} is not
-   *     {@link ProvisionStrategy#PROVIDER}.
-   */
-  Implementation<? extends Provider<? extends T>> getProvider();
-
-  /**
-   * Returns the scope applied to this implementation, or null if there is none.
-   */
-  Scope getScope();
-
-  /**
-   * Returns all keys which resolve to this implementation.
-   */
-  Set<Key<? super T>> getKeys();
-
-  /**
-   * Returns a Dependency instance for each dependency this implementation has;
-   * that is, "everyone we depend on."
-   */
-  Set<Dependency<?>> getDependencies();
-
-  /**
-   * Returns a Dependency instance for each dependent this implementation has;
-   * that is, "everyone who depends on us."
-   */
-  Set<Dependency<?>> getDependents();
-}
diff --git a/src/com/google/inject/introspect/Resolver.java b/src/com/google/inject/introspect/Resolver.java
deleted file mode 100644
index 7b7b128..0000000
--- a/src/com/google/inject/introspect/Resolver.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.google.inject.introspect;
-
-import com.google.inject.Key;
-import java.util.Set;
-
-/**
- * The resolver is used by the Injector to, given an injection request (key),
- * find the appropriate instructions for obtaining instances to fulfill that
- * request.  It is exposed for use by tools.
- *
- * @author Kevin Bourrillion (kevinb9n@gmail.com)
- */
-public interface Resolver {
-
-  /**
-   * Returns the Implementation that the given key resolves to
-   * @throws IllegalArgumentException if the key cannot be resolved
-   */
-  <T> Implementation<T> resolve(Key<? super T> key);
-
-  /**
-   * Returns all the keys that can be resolved by this injector.
-   */
-  Set<Key<?>> allKeys();
-
-  /**
-   * Returns all the implementations known to this injector.
-   */
-  Set<Implementation<?>> resolveAll();
-}
diff --git a/src/com/google/inject/spi/BindingVisitor.java b/src/com/google/inject/spi/BindingVisitor.java
new file mode 100644
index 0000000..4faabac
--- /dev/null
+++ b/src/com/google/inject/spi/BindingVisitor.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.Binding;
+
+/**
+ * Visits bindings. Pass an implementation of {@code BindingVisitor} to
+ * {@link com.google.inject.Binding#accept(BindingVisitor)} and the binding
+ * will call back to the appropriate visitor method for its type.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public interface BindingVisitor<T> {
+
+  /**
+   * Visits a linked binding.
+   */
+  void visit(LinkedBinding<? extends T> binding);
+
+  /**
+   * Visits a binding to an instance.
+   */
+  void visit(InstanceBinding<? extends T> binding);
+
+  /**
+   * Visits a binding to a provider instance.
+   */
+  void visit(ProviderInstanceBinding<? extends T> binding);
+
+  /**
+   * Visits a binding to provider which is also bound.
+   */
+  void visit(ProviderBinding<? extends T> binding);
+
+  /**
+   * Visits a class binding.
+   */
+  void visit(ClassBinding<? extends T> binding);
+
+  /**
+   * Visits a constant binding.
+   */
+  void visit(ConstantBinding<? extends T> binding);
+
+  /**
+   * Visits a binding of unknown type. This method will be called for internal
+   * bindings and for future binding types which your visitor doesn't know
+   * about.
+   */
+  void visitUnknown(Binding<? extends T> binding);
+}
diff --git a/src/com/google/inject/spi/ClassBinding.java b/src/com/google/inject/spi/ClassBinding.java
new file mode 100644
index 0000000..f9eb6fa
--- /dev/null
+++ b/src/com/google/inject/spi/ClassBinding.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.Binding;
+
+/**
+ * A binding to a concrete, injectable class. Instantiates new instances of the
+ * class and injects its members.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public interface ClassBinding<T> extends Binding<T>, HasDependencies {
+
+  /**
+   * Gets the class associated with this binding.
+   */
+  Class<T> getBoundClass();
+}
diff --git a/src/com/google/inject/spi/ConstantBinding.java b/src/com/google/inject/spi/ConstantBinding.java
new file mode 100644
index 0000000..b96a87b
--- /dev/null
+++ b/src/com/google/inject/spi/ConstantBinding.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.Binding;
+
+/**
+ * A binding to a constant.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public interface ConstantBinding<T> extends Binding<T> {
+
+  /**
+   * Gets the constant value associated with this binding.
+   */
+  T getValue();
+}
diff --git a/src/com/google/inject/spi/HasDependencies.java b/src/com/google/inject/spi/HasDependencies.java
new file mode 100644
index 0000000..7b54fab
--- /dev/null
+++ b/src/com/google/inject/spi/HasDependencies.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+/**
+ * Implemented by bindings which have implementation dependencies on other
+ * bindings.
+ */
+public interface HasDependencies {
+
+  // TODO: Provide list of dependencies.
+}
diff --git a/src/com/google/inject/spi/InstanceBinding.java b/src/com/google/inject/spi/InstanceBinding.java
new file mode 100644
index 0000000..33c71f4
--- /dev/null
+++ b/src/com/google/inject/spi/InstanceBinding.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.Binding;
+
+/**
+ * A binding to a single instance.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public interface InstanceBinding<T> extends Binding<T>, HasDependencies {
+
+  /**
+   * Gets the instance associated with this binding.
+   */
+  T getInstance();
+}
diff --git a/src/com/google/inject/spi/LinkedBinding.java b/src/com/google/inject/spi/LinkedBinding.java
new file mode 100644
index 0000000..8440d61
--- /dev/null
+++ b/src/com/google/inject/spi/LinkedBinding.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.Binding;
+
+/**
+ * A binding that links to another binding.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public interface LinkedBinding<T> extends Binding<T> {
+
+  /**
+   * Gets the target of this link.
+   */
+  Binding<? extends T> getTarget();
+}
diff --git a/src/com/google/inject/spi/ProviderBinding.java b/src/com/google/inject/spi/ProviderBinding.java
new file mode 100644
index 0000000..660a119
--- /dev/null
+++ b/src/com/google/inject/spi/ProviderBinding.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.Binding;
+import com.google.inject.Provider;
+import com.google.inject.Key;
+
+/**
+ * A binding to a provider which is also bound.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public interface ProviderBinding<T> extends Binding<T> {
+
+  /**
+   * Gets the binding for the provider of this binding.
+   */
+  Binding<? extends Provider<? extends T>> getProviderBinding();
+}
diff --git a/src/com/google/inject/spi/ProviderInstanceBinding.java b/src/com/google/inject/spi/ProviderInstanceBinding.java
new file mode 100644
index 0000000..913eef8
--- /dev/null
+++ b/src/com/google/inject/spi/ProviderInstanceBinding.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 com.google.inject.spi;
+
+import com.google.inject.Binding;
+import com.google.inject.Provider;
+
+/**
+ * A binding to a single provider instance.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public interface ProviderInstanceBinding<T> extends Binding<T>,
+    HasDependencies {
+
+  /**
+   * Gets the raw (unscoped) provider instance associated with this binding.
+   */
+  Provider<? extends T> getProviderInstance();
+}
diff --git a/src/com/google/inject/spi/SourceProviders.java b/src/com/google/inject/spi/SourceProviders.java
index 30efb85..9da87db 100644
--- a/src/com/google/inject/spi/SourceProviders.java
+++ b/src/com/google/inject/spi/SourceProviders.java
@@ -30,6 +30,9 @@
 
   private SourceProviders() {}
 
+  /**
+   * Indicates that the source is unknown.
+   */
   public static final Object UNKNOWN_SOURCE = "[unknown source]";
   
   static final SourceProvider DEFAULT_INSTANCE = new StacktraceSourceProvider();
@@ -50,6 +53,7 @@
    * <p>Skipping only takes place after this method is called.
    */
   public synchronized static void skip(Class<?> clazz) {
+    // Poor man's copy-on-write hash set.
     Set<String> copy = new HashSet<String>();
     copy.addAll(skippedClassNames);
     copy.add(clazz.getName());