wire: FieldsOf now provides a pointer to the field type as well as the actual field type (#209)
This commit is contained in:
@@ -84,6 +84,10 @@ type call struct {
|
||||
|
||||
valueExpr ast.Expr
|
||||
valueTypeInfo *types.Info
|
||||
|
||||
// The following are only set for kind == selectorExpr:
|
||||
|
||||
ptrToField bool
|
||||
}
|
||||
|
||||
// solve finds the sequence of calls required to produce an output type
|
||||
@@ -226,14 +230,18 @@ dfs:
|
||||
index.Set(curr.t, errAbort)
|
||||
continue dfs
|
||||
}
|
||||
// Use the args[0] to store the position of the parent struct.
|
||||
// Use args[0] to store the position of the parent struct.
|
||||
args := []int{v.(int)}
|
||||
// len(f.Out) is always 2; if curr.t is the 2nd one, then the call must
|
||||
// provide a pointer to the field.
|
||||
ptrToField := types.Identical(curr.t, f.Out[1])
|
||||
calls = append(calls, call{
|
||||
kind: selectorExpr,
|
||||
pkg: f.Pkg,
|
||||
name: f.Name,
|
||||
out: curr.t,
|
||||
args: args,
|
||||
kind: selectorExpr,
|
||||
pkg: f.Pkg,
|
||||
name: f.Name,
|
||||
out: curr.t,
|
||||
args: args,
|
||||
ptrToField: ptrToField,
|
||||
})
|
||||
default:
|
||||
panic("unknown return value from ProviderSet.For")
|
||||
@@ -382,12 +390,14 @@ func buildProviderMap(fset *token.FileSet, hasher typeutil.Hasher, set *Provider
|
||||
}
|
||||
for _, f := range set.Fields {
|
||||
src := &providerSetSrc{Field: f}
|
||||
if prevSrc := srcMap.At(f.Out); prevSrc != nil {
|
||||
ec.add(bindingConflictError(fset, f.Out, set, src, prevSrc.(*providerSetSrc)))
|
||||
continue
|
||||
for _, typ := range f.Out {
|
||||
if prevSrc := srcMap.At(typ); prevSrc != nil {
|
||||
ec.add(bindingConflictError(fset, typ, set, src, prevSrc.(*providerSetSrc)))
|
||||
continue
|
||||
}
|
||||
providerMap.Set(typ, &ProvidedType{t: typ, f: f})
|
||||
srcMap.Set(typ, src)
|
||||
}
|
||||
providerMap.Set(f.Out, &ProvidedType{t: f.Out, f: f})
|
||||
srcMap.Set(f.Out, src)
|
||||
}
|
||||
if len(ec.errors) > 0 {
|
||||
return nil, nil, ec.errors
|
||||
|
||||
@@ -220,7 +220,7 @@ type InjectorArgs struct {
|
||||
Pos token.Pos
|
||||
}
|
||||
|
||||
// Field describes a list of fields from a struct.
|
||||
// Field describes a specific field selected from a struct.
|
||||
type Field struct {
|
||||
// Parent is the struct or pointer to the struct that the field belongs to.
|
||||
Parent types.Type
|
||||
@@ -231,8 +231,9 @@ type Field struct {
|
||||
// Pos is the source position of the field declaration.
|
||||
// defining these fields.
|
||||
Pos token.Pos
|
||||
// Out is the field's type.
|
||||
Out types.Type
|
||||
// Out is the field's provided types. The first element provides the
|
||||
// field type, the second element provides a pointer to it.
|
||||
Out []types.Type
|
||||
}
|
||||
|
||||
// Load finds all the provider sets in the packages that match the given
|
||||
@@ -458,7 +459,7 @@ func newObjectCache(pkgs []*packages.Package) *objectCache {
|
||||
}
|
||||
|
||||
// get converts a Go object into a Wire structure. It may return a *Provider, an
|
||||
// *IfaceBinding, a *ProviderSet, a *Value, or a *Fields.
|
||||
// *IfaceBinding, a *ProviderSet, a *Value, or a []*Field.
|
||||
func (oc *objectCache) get(obj types.Object) (val interface{}, errs []error) {
|
||||
ref := objRef{
|
||||
importPath: obj.Pkg().Path(),
|
||||
@@ -515,7 +516,7 @@ func (oc *objectCache) varDecl(obj *types.Var) *ast.ValueSpec {
|
||||
}
|
||||
|
||||
// processExpr converts an expression into a Wire structure. It may return a
|
||||
// *Provider, an *IfaceBinding, a *ProviderSet, a *Value or a *Field.
|
||||
// *Provider, an *IfaceBinding, a *ProviderSet, a *Value or a []*Field.
|
||||
func (oc *objectCache) processExpr(info *types.Info, pkgPath string, expr ast.Expr, varName string) (interface{}, []error) {
|
||||
exprPos := oc.fset.Position(expr.Pos())
|
||||
expr = astutil.Unparen(expr)
|
||||
@@ -988,7 +989,7 @@ func processInterfaceValue(fset *token.FileSet, info *types.Info, call *ast.Call
|
||||
}, nil
|
||||
}
|
||||
|
||||
// processFieldsOf creates a list of fields from a wire.FieldsOf call.
|
||||
// processFieldsOf creates a slice of fields from a wire.FieldsOf call.
|
||||
func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr) ([]*Field, error) {
|
||||
// Assumes that call.Fun is wire.FieldsOf.
|
||||
|
||||
@@ -1034,7 +1035,7 @@ func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr)
|
||||
Name: v.Name(),
|
||||
Pkg: v.Pkg(),
|
||||
Pos: v.Pos(),
|
||||
Out: v.Type(),
|
||||
Out: []types.Type{v.Type(), types.NewPointer(v.Type())},
|
||||
})
|
||||
}
|
||||
return fields, nil
|
||||
|
||||
@@ -26,4 +26,5 @@ func provideS() S {
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectedMessage())
|
||||
fmt.Println("pointer to " + *injectedMessagePtr())
|
||||
}
|
||||
|
||||
@@ -26,3 +26,10 @@ func injectedMessage() string {
|
||||
wire.FieldsOf(new(S), "Foo"))
|
||||
return ""
|
||||
}
|
||||
|
||||
func injectedMessagePtr() *string {
|
||||
wire.Build(
|
||||
provideS,
|
||||
wire.FieldsOf(new(S), "Foo"))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Hello, World!
|
||||
pointer to Hello, World!
|
||||
|
||||
@@ -12,3 +12,9 @@ func injectedMessage() string {
|
||||
string2 := s.Foo
|
||||
return string2
|
||||
}
|
||||
|
||||
func injectedMessagePtr() *string {
|
||||
s := provideS()
|
||||
string2 := &s.Foo
|
||||
return string2
|
||||
}
|
||||
|
||||
@@ -731,10 +731,14 @@ func (ig *injectorGen) valueExpr(lname string, c *call) {
|
||||
|
||||
func (ig *injectorGen) fieldExpr(lname string, c *call) {
|
||||
a := c.args[0]
|
||||
ig.p("\t%s := ", lname)
|
||||
if c.ptrToField {
|
||||
ig.p("&")
|
||||
}
|
||||
if a < len(ig.paramNames) {
|
||||
ig.p("\t%s := %s.%s\n", lname, ig.paramNames[a], c.name)
|
||||
ig.p("%s.%s\n", ig.paramNames[a], c.name)
|
||||
} else {
|
||||
ig.p("\t%s := %s.%s\n", lname, ig.localNames[a-len(ig.paramNames)], c.name)
|
||||
ig.p("%s.%s\n", ig.localNames[a-len(ig.paramNames)], c.name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user