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

@@ -232,9 +232,9 @@ dfs:
}
// 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
// If f.Out has 2 elements and curr.t is the 2nd one, then the call must
// 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{
kind: selectorExpr,
pkg: f.Pkg,

View File

@@ -232,7 +232,8 @@ type Field struct {
// defining these fields.
Pos token.Pos
// 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
}
@@ -1006,6 +1007,7 @@ func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr)
}
var struc *types.Struct
isPtrToStruct := false
switch t := structPtr.Elem().Underlying().(type) {
case *types.Pointer:
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()),
fmt.Errorf(firstArgReqFormat, types.TypeString(struc, nil)))
}
isPtrToStruct = true
case *types.Struct:
struc = t
default:
@@ -1030,12 +1033,18 @@ func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr)
if err != nil {
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{
Parent: structPtr.Elem(),
Name: v.Name(),
Pkg: v.Pkg(),
Pos: v.Pos(),
Out: []types.Type{v.Type(), types.NewPointer(v.Type())},
Out: out,
})
}
return fields, nil

View File

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

View File

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

View File

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

View File

@@ -12,9 +12,3 @@ func injectedMessage() string {
string2 := s.Foo
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() {
fmt.Println(injectedMessage())
fmt.Println("pointer to " + *injectedMessagePtr())
}

View File

@@ -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
}

View File

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

View File

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