wire: wire.FieldsOf should not provide pointer to field type for non-pointer structs (#210)

This commit is contained in:
Robert van Gent
2019-09-05 14:17:17 -07:00
committed by GitHub
parent f85ec5c4a6
commit c385f07c5d
16 changed files with 100 additions and 23 deletions

View File

@@ -423,7 +423,8 @@ func injectedMessage() string {
``` ```
You can add as many field names to a `wire.FieldsOf` function as you like. You can add as many field names to a `wire.FieldsOf` function as you like.
For a given field type `T`, `FieldsOf` provides both `T` and `*T`. For a given field type `T`, `FieldsOf` provides at least `T`; if the struct
argument is a pointer to a struct, then `FieldsOf` also provides `*T`.
### Cleanup functions ### Cleanup functions

View File

@@ -232,9 +232,9 @@ dfs:
} }
// Use 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)} args := []int{v.(int)}
// len(f.Out) is always 2; if curr.t is the 2nd one, then the call must // If f.Out has 2 elements and curr.t is the 2nd one, then the call must
// provide a pointer to the field. // provide a pointer to the field.
ptrToField := types.Identical(curr.t, f.Out[1]) ptrToField := len(f.Out) == 2 && types.Identical(curr.t, f.Out[1])
calls = append(calls, call{ calls = append(calls, call{
kind: selectorExpr, kind: selectorExpr,
pkg: f.Pkg, pkg: f.Pkg,

View File

@@ -232,7 +232,8 @@ type Field struct {
// defining these fields. // defining these fields.
Pos token.Pos Pos token.Pos
// Out is the field's provided types. The first element provides the // Out is the field's provided types. The first element provides the
// field type, the second element provides a pointer to it. // field type. If the field is coming from a pointer to a struct,
// there will be a second element providing a pointer to the field.
Out []types.Type Out []types.Type
} }
@@ -1006,6 +1007,7 @@ func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr)
} }
var struc *types.Struct var struc *types.Struct
isPtrToStruct := false
switch t := structPtr.Elem().Underlying().(type) { switch t := structPtr.Elem().Underlying().(type) {
case *types.Pointer: case *types.Pointer:
struc, ok = t.Elem().Underlying().(*types.Struct) struc, ok = t.Elem().Underlying().(*types.Struct)
@@ -1013,6 +1015,7 @@ func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr)
return nil, notePosition(fset.Position(call.Pos()), return nil, notePosition(fset.Position(call.Pos()),
fmt.Errorf(firstArgReqFormat, types.TypeString(struc, nil))) fmt.Errorf(firstArgReqFormat, types.TypeString(struc, nil)))
} }
isPtrToStruct = true
case *types.Struct: case *types.Struct:
struc = t struc = t
default: default:
@@ -1030,12 +1033,18 @@ func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr)
if err != nil { if err != nil {
return nil, notePosition(fset.Position(call.Pos()), err) return nil, notePosition(fset.Position(call.Pos()), err)
} }
out := []types.Type{v.Type()}
if isPtrToStruct {
// If the field is from a pointer to a struct, then
// wire.Fields also provides a pointer to the field.
out = append(out, types.NewPointer(v.Type()))
}
fields = append(fields, &Field{ fields = append(fields, &Field{
Parent: structPtr.Elem(), Parent: structPtr.Elem(),
Name: v.Name(), Name: v.Name(),
Pkg: v.Pkg(), Pkg: v.Pkg(),
Pos: v.Pos(), Pos: v.Pos(),
Out: []types.Type{v.Type(), types.NewPointer(v.Type())}, Out: out,
}) })
} }
return fields, nil return fields, nil

View File

@@ -26,5 +26,4 @@ func provideS() S {
func main() { func main() {
fmt.Println(injectedMessage()) fmt.Println(injectedMessage())
fmt.Println("pointer to " + *injectedMessagePtr())
} }

View File

@@ -26,10 +26,3 @@ func injectedMessage() string {
wire.FieldsOf(new(S), "Foo")) wire.FieldsOf(new(S), "Foo"))
return "" return ""
} }
func injectedMessagePtr() *string {
wire.Build(
provideS,
wire.FieldsOf(new(S), "Foo"))
return nil
}

View File

@@ -1,2 +1 @@
Hello, World! Hello, World!
pointer to Hello, World!

View File

@@ -12,9 +12,3 @@ func injectedMessage() string {
string2 := s.Foo string2 := s.Foo
return string2 return string2
} }
func injectedMessagePtr() *string {
s := provideS()
string2 := &s.Foo
return string2
}

View File

@@ -0,0 +1,29 @@
// Copyright 2019 The Wire Authors
//
// 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
//
// https://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 main
import "fmt"
type S struct {
Foo string
}
func provideS() S {
return S{Foo: "Hello, World!"}
}
func main() {
fmt.Println("pointer to " + *injectedMessagePtr())
}

View File

@@ -0,0 +1,32 @@
// Copyright 2019 The Wire Authors
//
// 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
//
// https://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.
//+build wireinject
package main
import (
"github.com/google/wire"
)
func injectedMessagePtr() *string {
// This shouldn't work; FieldsOf provides a pointer to the
// field only when the struct type is a pointer to a struct.
// See FieldsOfStructPointer for a working example using
// a pointer to a struct.
wire.Build(
provideS,
wire.FieldsOf(new(S), "Foo"))
return nil
}

View File

@@ -0,0 +1 @@
example.com/foo

View File

@@ -0,0 +1 @@
example.com/foo/wire.go:x:y: inject injectedMessagePtr: no provider found for *string, output of injector

View File

@@ -26,4 +26,5 @@ func provideS() *S {
func main() { func main() {
fmt.Println(injectedMessage()) fmt.Println(injectedMessage())
fmt.Println("pointer to " + *injectedMessagePtr())
} }

View File

@@ -26,3 +26,10 @@ func injectedMessage() string {
wire.FieldsOf(new(*S), "Foo")) wire.FieldsOf(new(*S), "Foo"))
return "" return ""
} }
func injectedMessagePtr() *string {
wire.Build(
provideS,
wire.FieldsOf(new(*S), "Foo"))
return nil
}

View File

@@ -1 +1,2 @@
Hello, World! Hello, World!
pointer to Hello, World!

View File

@@ -12,3 +12,9 @@ func injectedMessage() string {
string2 := s.Foo string2 := s.Foo
return string2 return string2
} }
func injectedMessagePtr() *string {
s := provideS()
string2 := &s.Foo
return string2
}

10
wire.go
View File

@@ -173,11 +173,11 @@ type StructFields struct{}
// to provide the types of those fields. The structType argument must be a // to provide the types of those fields. The structType argument must be a
// pointer to the struct or a pointer to a pointer to the struct it wishes to reference. // pointer to the struct or a pointer to a pointer to the struct it wishes to reference.
// //
// The following example would provide *Foo and *Bar using S.MyFoo and S.MyBar respectively: // The following example would provide Foo and Bar using S.MyFoo and S.MyBar respectively:
// //
// type S struct { // type S struct {
// MyFoo *Foo // MyFoo Foo
// MyBar *Bar // MyBar Bar
// } // }
// //
// func NewStruct() S { /* ... */ } // func NewStruct() S { /* ... */ }
@@ -187,6 +187,10 @@ type StructFields struct{}
// //
// func NewStruct() *S { /* ... */ } // func NewStruct() *S { /* ... */ }
// var Set = wire.NewSet(wire.FieldsOf(new(*S), "MyFoo", "MyBar")) // var Set = wire.NewSet(wire.FieldsOf(new(*S), "MyFoo", "MyBar"))
//
// If the structType argument is a pointer to a pointer to a struct, then FieldsOf
// additionally provides a pointer to each field type (e.g., *Foo and *Bar in the
// example above).
func FieldsOf(structType interface{}, fieldNames ...string) StructFields { func FieldsOf(structType interface{}, fieldNames ...string) StructFields {
return StructFields{} return StructFields{}
} }