diff --git a/internal/wire/analyze.go b/internal/wire/analyze.go index d7f59ab..c3ca1cb 100644 --- a/internal/wire/analyze.go +++ b/internal/wire/analyze.go @@ -114,8 +114,8 @@ dfs: continue } - switch pv := set.For(curr.t); { - case pv.IsNil(): + pv := set.For(curr.t) + if pv.IsNil() { if curr.from == nil { ec.add(fmt.Errorf("no provider found for %s, output of injector", types.TypeString(curr.t, nil))) index.Set(curr.t, errAbort) @@ -129,33 +129,25 @@ dfs: ec.add(errors.New(sb.String())) index.Set(curr.t, errAbort) continue - case pv.IsArg(): - src := set.srcMap.At(curr.t).(*providerSetSrc) - used = append(used, src) - if concrete := pv.ConcreteType(); !types.Identical(concrete, curr.t) { - // Interface binding. - i := index.At(concrete) - if i == nil { - stk = append(stk, curr, frame{t: concrete, from: curr.t, up: &curr}) - continue - } - index.Set(curr.t, i) - } - continue - case pv.IsProvider(): - p := pv.Provider() - src := set.srcMap.At(curr.t).(*providerSetSrc) - used = append(used, src) - if concrete := pv.ConcreteType(); !types.Identical(concrete, curr.t) { - // Interface binding. Don't create a call ourselves. - i := index.At(concrete) - if i == nil { - stk = append(stk, curr, frame{t: concrete, from: curr.t, up: &curr}) - continue - } - index.Set(curr.t, i) + } + src := set.srcMap.At(curr.t).(*providerSetSrc) + used = append(used, src) + if concrete := pv.Type(); !types.Identical(concrete, curr.t) { + // Interface binding does not create a call. + i := index.At(concrete) + if i == nil { + stk = append(stk, curr, frame{t: concrete, from: curr.t, up: &curr}) continue } + index.Set(curr.t, i) + continue + } + + switch pv := set.For(curr.t); { + case pv.IsArg(): + // Continue, already added to stk. + case pv.IsProvider(): + p := pv.Provider() // Ensure that all argument types have been visited. If not, push them // on the stack in reverse order so that calls are added in argument // order. @@ -204,18 +196,6 @@ dfs: }) case pv.IsValue(): v := pv.Value() - if !types.Identical(v.Out, curr.t) { - // Interface binding. Don't create a call ourselves. - i := index.At(v.Out) - if i == nil { - stk = append(stk, curr, frame{t: v.Out, from: curr.t, up: &curr}) - continue - } - index.Set(curr.t, i) - continue - } - src := set.srcMap.At(curr.t).(*providerSetSrc) - used = append(used, src) index.Set(curr.t, given.Len()+len(calls)) calls = append(calls, call{ kind: valueExpr, diff --git a/internal/wire/parse.go b/internal/wire/parse.go index 75a7b19..a2abf89 100644 --- a/internal/wire/parse.go +++ b/internal/wire/parse.go @@ -939,8 +939,14 @@ func (pt ProvidedType) IsNil() bool { return pt.p == nil && pt.v == nil && pt.a == nil } -// ConcreteType returns the concrete type that was provided. -func (pt ProvidedType) ConcreteType() types.Type { +// Type returns the output type. +// +// - For a function provider, this is the first return value type. +// - For a struct provider, this is either the struct type or the pointer type +// whose element type is the struct type. +// - For a value, this is the type of the expression. +// - For an argument, this is the type of the argument. +func (pt ProvidedType) Type() types.Type { return pt.t } diff --git a/internal/wire/testdata/BindInterfaceWithValue/foo/foo.go b/internal/wire/testdata/BindInterfaceWithValue/foo/foo.go new file mode 100644 index 0000000..8238166 --- /dev/null +++ b/internal/wire/testdata/BindInterfaceWithValue/foo/foo.go @@ -0,0 +1,20 @@ +// Copyright 2018 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 + +func main() { + w := inject() + w.Write([]byte("Hello, World!")) +} diff --git a/internal/wire/testdata/BindInterfaceWithValue/foo/wire.go b/internal/wire/testdata/BindInterfaceWithValue/foo/wire.go new file mode 100644 index 0000000..4353bf5 --- /dev/null +++ b/internal/wire/testdata/BindInterfaceWithValue/foo/wire.go @@ -0,0 +1,32 @@ +// Copyright 2018 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 ( + "io" + "os" + + "github.com/google/wire" +) + +func inject() io.Writer { + wire.Build( + wire.Value(os.Stdout), + wire.Bind(new(io.Writer), new(os.File)), + ) + return nil +} diff --git a/internal/wire/testdata/BindInterfaceWithValue/pkg b/internal/wire/testdata/BindInterfaceWithValue/pkg new file mode 100644 index 0000000..f7a5c8c --- /dev/null +++ b/internal/wire/testdata/BindInterfaceWithValue/pkg @@ -0,0 +1 @@ +example.com/foo diff --git a/internal/wire/testdata/BindInterfaceWithValue/want/program_out.txt b/internal/wire/testdata/BindInterfaceWithValue/want/program_out.txt new file mode 100644 index 0000000..b45ef6f --- /dev/null +++ b/internal/wire/testdata/BindInterfaceWithValue/want/program_out.txt @@ -0,0 +1 @@ +Hello, World! \ No newline at end of file diff --git a/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go b/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go new file mode 100644 index 0000000..6fb9db4 --- /dev/null +++ b/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go @@ -0,0 +1,22 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate wire +//+build !wireinject + +package main + +import ( + "io" + "os" +) + +// Injectors from wire.go: + +func inject() io.Writer { + file := _wireFileValue + return file +} + +var ( + _wireFileValue = os.Stdout +)