Repository: google/wire (go)

Issue:
wire: improve error message when a provider set includes a binding but not the corresponding concrete type
### Describe the bug

A wire set containing __subsets__ (one or more wire sets), should be just the same as a wire set with items from that subsets added directly.

### To Reproduce

Given this code:

__master.go__
```go
package wirebug

type ISomeInterface interface {
	DoStuff(thing string) int
}

type SomeStuff struct{}

func (si *SomeStuff) DoStuff(thing string) int {
	return len(thing)
}

func NewStuff() *SomeStuff {
	return &SomeStuff{}
}
```

__wiring.go__
```go
package wirebug

import "github.com/google/wire"

var WiringProviders = wire.NewSet(
	NewStuff,
)

var WiringBindings = wire.NewSet(
	wire.Bind(new(ISomeInterface), new(SomeStuff)),
)

var WiringSet = wire.NewSet(
	WiringProviders,
	WiringBindings,
)
```

__injectors.go__
```go
//+build wireinject

package wirebug

import "github.com/google/wire"

func InjectStuff() ISomeInterface {
	wire.Build(WiringSet)
	return nil
}
```

Running `wire ./...` results in an error:
```
$$$/wirebug/wiring.go:10:2: no binding for *$$$/wirebug.SomeStuff
wire: at least one generate failure
```
It's as if items from `WiringProviders` can't be seen by `WiringBindings` although they're inside `WiringSet`. Inside the documentation of `wire.NewSet`, there's this statement, **"Passing a ProviderSet to NewSet is the same as if the set's contents were passed as arguments to NewSet directly."**, but it turns out that it's not so.

## Expected behavior

The file `wire_gen.go` should be generated without problem.

Both of these `WiringSet`
```go
var WiringProviders = wire.NewSet(
	NewStuff,
)

var WiringBindings = wire.NewSet(
	wire.Bind(new(ISomeInterface), new(SomeStuff)),
)

var WiringSet = wire.NewSet(
	WiringProviders,
	WiringBindings,
)
```
and
```go
var WiringSet = wire.NewSet(
	NewStuff,
	wire.Bind(new(ISomeInterface), new(SomeStuff)),
)
```
should behave the same. But only the below version works.

### Version

Version 0.2.1

### Additional context

None.


Pull request:
wire: improve error for a provider set with a binding but no corresponding provider
Fixes #113.

Patch:
diff --git a/internal/wire/analyze.go b/internal/wire/analyze.go
index 11d1189..72fd8a6 100644
--- a/internal/wire/analyze.go
+++ b/internal/wire/analyze.go
@@ -353,9 +353,11 @@ func buildProviderMap(fset *token.FileSet, hasher typeutil.Hasher, set *Provider
 		}
 		concrete := providerMap.At(b.Provided)
 		if concrete == nil {
-			pos := fset.Position(b.Pos)
-			typ := types.TypeString(b.Provided, nil)
-			ec.add(notePosition(pos, fmt.Errorf("no binding for %s", typ)))
+			setName := set.VarName
+			if setName == "" {
+				setName = "provider set"
+			}
+			ec.add(notePosition(fset.Position(b.Pos), fmt.Errorf("wire.Bind of concrete type %q to interface %q, but %s does not include a provider for %q", b.Provided, b.Iface, setName, b.Provided)))
 			continue
 		}
 		providerMap.Set(b.Iface, concrete)
@@ -438,12 +440,10 @@ func verifyAcyclic(providerMap *typeutil.Map, hasher typeutil.Hasher) []error {
 // for the same output type.
 func bindingConflictError(fset *token.FileSet, typ types.Type, set *ProviderSet, cur, prev *providerSetSrc) error {
 	sb := new(strings.Builder)
-	if set.VarName == "" {
-		fmt.Fprintf(sb, "wire.Build")
-	} else {
-		fmt.Fprintf(sb, set.VarName)
+	if set.VarName != "" {
+		fmt.Fprintf(sb, "%s has ", set.VarName)
 	}
-	fmt.Fprintf(sb, " has multiple bindings for %s\n", types.TypeString(typ, nil))
+	fmt.Fprintf(sb, "multiple bindings for %s\n", types.TypeString(typ, nil))
 	fmt.Fprintf(sb, "current:\n<- %s\n", strings.Join(cur.trace(fset, typ), "\n<- "))
 	fmt.Fprintf(sb, "previous:\n<- %s", strings.Join(prev.trace(fset, typ), "\n<- "))
 	return notePosition(fset.Position(set.Pos), errors.New(sb.String()))
diff --git a/internal/wire/wire.go b/internal/wire/wire.go
index 089dc7f..7c1e573 100644
--- a/internal/wire/wire.go
+++ b/internal/wire/wire.go
@@ -276,7 +276,7 @@ func (g *gen) frame() []byte {
 	if len(g.anonImports) > 0 {
 		buf.WriteString("import (\n")
 		anonImps := make([]string, 0, len(g.anonImports))
-		for path, _ := range g.anonImports {
+		for path := range g.anonImports {
 			anonImps = append(anonImps, path)
 		}
 		sort.Strings(anonImps)


Test patch:
diff --git a/internal/wire/testdata/InjectInputConflict/want/wire_errs.txt b/internal/wire/testdata/InjectInputConflict/want/wire_errs.txt
index 7ab4d29..988de2f 100644
--- a/internal/wire/testdata/InjectInputConflict/want/wire_errs.txt
+++ b/internal/wire/testdata/InjectInputConflict/want/wire_errs.txt
@@ -1,4 +1,4 @@
-example.com/foo/wire.go:x:y: wire.Build has multiple bindings for example.com/foo.Foo
+example.com/foo/wire.go:x:y: multiple bindings for example.com/foo.Foo
 current:
 <- provider "provideFoo" (example.com/foo/foo.go:x:y)
 <- provider set "Set" (example.com/foo/foo.go:x:y)
diff --git a/internal/wire/testdata/MultipleArgsSameType/want/wire_errs.txt b/internal/wire/testdata/MultipleArgsSameType/want/wire_errs.txt
index 7a56e43..f23405d 100644
--- a/internal/wire/testdata/MultipleArgsSameType/want/wire_errs.txt
+++ b/internal/wire/testdata/MultipleArgsSameType/want/wire_errs.txt
@@ -1,4 +1,4 @@
-example.com/foo/wire.go:x:y: wire.Build has multiple bindings for string
+example.com/foo/wire.go:x:y: multiple bindings for string
 current:
 <- argument b to injector function inject (example.com/foo/wire.go:x:y)
 previous:
diff --git a/internal/wire/testdata/MultipleBindings/want/wire_errs.txt b/internal/wire/testdata/MultipleBindings/want/wire_errs.txt
index 9379f9c..9944000 100644
--- a/internal/wire/testdata/MultipleBindings/want/wire_errs.txt
+++ b/internal/wire/testdata/MultipleBindings/want/wire_errs.txt
@@ -1,17 +1,17 @@
-example.com/foo/wire.go:x:y: wire.Build has multiple bindings for example.com/foo.Foo
+example.com/foo/wire.go:x:y: multiple bindings for example.com/foo.Foo
 current:
 <- provider "provideFooAgain" (example.com/foo/foo.go:x:y)
 previous:
 <- provider "provideFoo" (example.com/foo/foo.go:x:y)
 
-example.com/foo/wire.go:x:y: wire.Build has multiple bindings for example.com/foo.Foo
+example.com/foo/wire.go:x:y: multiple bindings for example.com/foo.Foo
 current:
 <- provider "provideFoo" (example.com/foo/foo.go:x:y)
 previous:
 <- provider "provideFoo" (example.com/foo/foo.go:x:y)
 <- provider set "Set" (example.com/foo/foo.go:x:y)
 
-example.com/foo/wire.go:x:y: wire.Build has multiple bindings for example.com/foo.Foo
+example.com/foo/wire.go:x:y: multiple bindings for example.com/foo.Foo
 current:
 <- provider "provideFoo" (example.com/foo/foo.go:x:y)
 previous:
@@ -28,13 +28,13 @@ previous:
 <- provider "provideFoo" (example.com/foo/foo.go:x:y)
 <- provider set "Set" (example.com/foo/foo.go:x:y)
 
-example.com/foo/wire.go:x:y: wire.Build has multiple bindings for example.com/foo.Foo
+example.com/foo/wire.go:x:y: multiple bindings for example.com/foo.Foo
 current:
 <- wire.Value (example.com/foo/wire.go:x:y)
 previous:
 <- provider "provideFoo" (example.com/foo/foo.go:x:y)
 
-example.com/foo/wire.go:x:y: wire.Build has multiple bindings for example.com/foo.Bar
+example.com/foo/wire.go:x:y: multiple bindings for example.com/foo.Bar
 current:
 <- wire.Bind (example.com/foo/wire.go:x:y)
 previous:
diff --git a/internal/wire/testdata/ProviderSetBindingMissingConcreteType/want/wire_errs.txt b/internal/wire/testdata/ProviderSetBindingMissingConcreteType/want/wire_errs.txt
index 76f1438..656cd94 100644
--- a/internal/wire/testdata/ProviderSetBindingMissingConcreteType/want/wire_errs.txt
+++ b/internal/wire/testdata/ProviderSetBindingMissingConcreteType/want/wire_errs.txt
@@ -1,1 +1,1 @@
-example.com/foo/foo.go:x:y: no binding for *example.com/foo.foo
\ No newline at end of file
+example.com/foo/foo.go:x:y: wire.Bind of concrete type "*example.com/foo.foo" to interface "example.com/foo.fooer", but setB does not include a provider for "*example.com/foo.foo"
\ No newline at end of file