wire: add info from the dependency graph when a type is not provided
This commit is contained in:
committed by
Ross Light
parent
b84ad6154f
commit
a8825fef58
@@ -122,6 +122,7 @@ func solve(fset *token.FileSet, out types.Type, given []types.Type, set *Provide
|
|||||||
type frame struct {
|
type frame struct {
|
||||||
t types.Type
|
t types.Type
|
||||||
from types.Type
|
from types.Type
|
||||||
|
up *frame
|
||||||
}
|
}
|
||||||
stk := []frame{{t: out}}
|
stk := []frame{{t: out}}
|
||||||
dfs:
|
dfs:
|
||||||
@@ -135,12 +136,15 @@ dfs:
|
|||||||
switch pv := set.For(curr.t); {
|
switch pv := set.For(curr.t); {
|
||||||
case pv.IsNil():
|
case pv.IsNil():
|
||||||
if curr.from == nil {
|
if curr.from == nil {
|
||||||
ec.add(fmt.Errorf("no provider found for %s (output of injector)", types.TypeString(curr.t, nil)))
|
ec.add(fmt.Errorf("no provider found for %s, output of injector", types.TypeString(curr.t, nil)))
|
||||||
index.Set(curr.t, errAbort)
|
index.Set(curr.t, errAbort)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO(light): Give name of provider.
|
neededBy := []string{types.TypeString(curr.t, nil)}
|
||||||
ec.add(fmt.Errorf("no provider found for %s (required by provider of %s)", types.TypeString(curr.t, nil), types.TypeString(curr.from, nil)))
|
for f := curr.up; f != nil; f = f.up {
|
||||||
|
neededBy = append(neededBy, fmt.Sprintf("%s in %s", types.TypeString(f.t, nil), set.srcMap.At(f.t).(*providerSetSrc).description(fset, f.t)))
|
||||||
|
}
|
||||||
|
ec.add(fmt.Errorf("no provider found for %s", strings.Join(neededBy, ", needed by ")))
|
||||||
index.Set(curr.t, errAbort)
|
index.Set(curr.t, errAbort)
|
||||||
continue
|
continue
|
||||||
case pv.IsProvider():
|
case pv.IsProvider():
|
||||||
@@ -151,7 +155,7 @@ dfs:
|
|||||||
// Interface binding. Don't create a call ourselves.
|
// Interface binding. Don't create a call ourselves.
|
||||||
i := index.At(concrete)
|
i := index.At(concrete)
|
||||||
if i == nil {
|
if i == nil {
|
||||||
stk = append(stk, curr, frame{t: concrete, from: curr.t})
|
stk = append(stk, curr, frame{t: concrete, from: curr.t, up: &curr})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
index.Set(curr.t, i)
|
index.Set(curr.t, i)
|
||||||
@@ -169,7 +173,7 @@ dfs:
|
|||||||
stk = append(stk, curr)
|
stk = append(stk, curr)
|
||||||
visitedArgs = false
|
visitedArgs = false
|
||||||
}
|
}
|
||||||
stk = append(stk, frame{t: a.Type, from: curr.t})
|
stk = append(stk, frame{t: a.Type, from: curr.t, up: &curr})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !visitedArgs {
|
if !visitedArgs {
|
||||||
@@ -208,7 +212,7 @@ dfs:
|
|||||||
// Interface binding. Don't create a call ourselves.
|
// Interface binding. Don't create a call ourselves.
|
||||||
i := index.At(v.Out)
|
i := index.At(v.Out)
|
||||||
if i == nil {
|
if i == nil {
|
||||||
stk = append(stk, curr, frame{t: v.Out, from: curr.t})
|
stk = append(stk, curr, frame{t: v.Out, from: curr.t, up: &curr})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
index.Set(curr.t, i)
|
index.Set(curr.t, i)
|
||||||
|
|||||||
@@ -38,34 +38,42 @@ type providerSetSrc struct {
|
|||||||
Import *ProviderSet
|
Import *ProviderSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace returns a slice of strings describing the (possibly recursive) source
|
// description returns a string describing the source of p, including line numbers.
|
||||||
// of p, including line numbers.
|
func (p *providerSetSrc) description(fset *token.FileSet, typ types.Type) string {
|
||||||
func (p *providerSetSrc) trace(fset *token.FileSet, typ types.Type) []string {
|
|
||||||
quoted := func(s string) string {
|
quoted := func(s string) string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%q ", s)
|
return fmt.Sprintf("%q ", s)
|
||||||
}
|
}
|
||||||
var retval []string
|
switch {
|
||||||
if p.Provider != nil {
|
case p.Provider != nil:
|
||||||
kind := "provider"
|
kind := "provider"
|
||||||
if p.Provider.IsStruct {
|
if p.Provider.IsStruct {
|
||||||
kind = "struct provider"
|
kind = "struct provider"
|
||||||
}
|
}
|
||||||
retval = append(retval, fmt.Sprintf("%s %s(%s)", kind, quoted(p.Provider.Name), fset.Position(p.Provider.Pos)))
|
return fmt.Sprintf("%s %s(%s)", kind, quoted(p.Provider.Name), fset.Position(p.Provider.Pos))
|
||||||
} else if p.Binding != nil {
|
case p.Binding != nil:
|
||||||
retval = append(retval, fmt.Sprintf("wire.Bind (%s)", fset.Position(p.Binding.Pos)))
|
return fmt.Sprintf("wire.Bind (%s)", fset.Position(p.Binding.Pos))
|
||||||
} else if p.Value != nil {
|
case p.Value != nil:
|
||||||
retval = append(retval, fmt.Sprintf("wire.Value (%s)", fset.Position(p.Value.Pos)))
|
return fmt.Sprintf("wire.Value (%s)", fset.Position(p.Value.Pos))
|
||||||
} else if p.Import != nil {
|
case p.Import != nil:
|
||||||
|
return fmt.Sprintf("provider set %s(%s)", quoted(p.Import.VarName), fset.Position(p.Import.Pos))
|
||||||
|
}
|
||||||
|
panic("providerSetSrc with no fields set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// trace returns a slice of strings describing the (possibly recursive) source
|
||||||
|
// of p, including line numbers.
|
||||||
|
func (p *providerSetSrc) trace(fset *token.FileSet, typ types.Type) []string {
|
||||||
|
var retval []string
|
||||||
|
// Only Imports need recursion.
|
||||||
|
if p.Import != nil {
|
||||||
if parent := p.Import.srcMap.At(typ); parent != nil {
|
if parent := p.Import.srcMap.At(typ); parent != nil {
|
||||||
retval = append(retval, parent.(*providerSetSrc).trace(fset, typ)...)
|
retval = append(retval, parent.(*providerSetSrc).trace(fset, typ)...)
|
||||||
}
|
}
|
||||||
retval = append(retval, fmt.Sprintf("provider set %s(%s)", quoted(p.Import.VarName), fset.Position(p.Import.Pos)))
|
|
||||||
} else {
|
|
||||||
panic("providerSetSrc with no fields set")
|
|
||||||
}
|
}
|
||||||
|
retval = append(retval, p.description(fset, typ))
|
||||||
return retval
|
return retval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ package main
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(injectBaz())
|
fmt.Println(injectMissingOutputType())
|
||||||
|
fmt.Println(injectMultipleMissingTypes())
|
||||||
|
fmt.Println(injectMissingRecursiveType())
|
||||||
}
|
}
|
||||||
|
|
||||||
type Foo int
|
type Foo int
|
||||||
@@ -27,3 +29,19 @@ type Baz int
|
|||||||
func provideBaz(foo Foo, bar Bar) Baz {
|
func provideBaz(foo Foo, bar Bar) Baz {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Zip int
|
||||||
|
type Zap int
|
||||||
|
type Zop int
|
||||||
|
|
||||||
|
func provideZip(foo Foo) Zip {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideZap(zip Zip) Zap {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideZop(zap Zap) Zop {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,23 @@ import (
|
|||||||
"github.com/google/go-cloud/wire"
|
"github.com/google/go-cloud/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
func injectBaz() Baz {
|
func injectMissingOutputType() Foo {
|
||||||
|
// Error: no provider for Foo.
|
||||||
|
wire.Build()
|
||||||
|
return Foo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func injectMultipleMissingTypes() Baz {
|
||||||
|
// Error: provideBaz needs Foo and Bar, both missing.
|
||||||
wire.Build(provideBaz)
|
wire.Build(provideBaz)
|
||||||
return Baz(0)
|
return Baz(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func injectMissingRecursiveType() Zop {
|
||||||
|
// Error:
|
||||||
|
// Zop -> Zap -> Zip -> Foo
|
||||||
|
// provideZop needs Zap, provideZap needs Zip, provideZip needs Foo,
|
||||||
|
// which is missing.
|
||||||
|
wire.Build(provideZop, provideZap, provideZip)
|
||||||
|
return Zop(0)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
no provider found for example.com/foo.Foo
|
inject injectMissingOutputType: no provider found for example.com/foo.Foo, output of injector
|
||||||
no provider found for example.com/foo.Bar
|
inject injectMultipleMissingTypes: no provider found for example.com/foo.Foo, needed by example.com/foo.Baz in provider "provideBaz" (/wire_gopath/src/example.com/foo/foo.go:29:6)
|
||||||
|
inject injectMultipleMissingTypes: no provider found for example.com/foo.Bar, needed by example.com/foo.Baz in provider "provideBaz" (/wire_gopath/src/example.com/foo/foo.go:29:6)
|
||||||
|
inject injectMissingRecursiveType: no provider found for example.com/foo.Foo, needed by example.com/foo.Zip in provider "provideZip" (/wire_gopath/src/example.com/foo/foo.go:37:6), needed by example.com/foo.Zap in provider "provideZap" (/wire_gopath/src/example.com/foo/foo.go:41:6), needed by example.com/foo.Zop in provider "provideZop" (/wire_gopath/src/example.com/foo/foo.go:45:6)
|
||||||
|
|||||||
Reference in New Issue
Block a user