Skip to content

Commit

Permalink
Support variadic provider and injector functions (#91)
Browse files Browse the repository at this point in the history
Fixes #61
  • Loading branch information
shantuo authored and zombiezen committed Dec 3, 2018
1 parent 65d810f commit ef9bb67
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 4 deletions.
4 changes: 4 additions & 0 deletions internal/wire/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ type call struct {
// This will be nil for kind == valueExpr.
args []int

// varargs is true if the provider function is variadic.
varargs bool

// fieldNames maps the arguments to struct field names.
// This will only be set if kind == structProvider.
fieldNames []string
Expand Down Expand Up @@ -192,6 +195,7 @@ dfs:
pkg: p.Pkg,
name: p.Name,
args: args,
varargs: p.Varargs,
fieldNames: p.Fields,
ins: ins,
out: curr.t,
Expand Down
4 changes: 4 additions & 0 deletions internal/wire/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ type Provider struct {
// Args is the list of data dependencies this provider has.
Args []ProviderInput

// Varargs is true if the provider function is variadic.
Varargs bool

// IsStruct is true if this provider is a named struct type.
// Otherwise it's a function.
IsStruct bool
Expand Down Expand Up @@ -639,6 +642,7 @@ func processFuncProvider(fset *token.FileSet, fn *types.Func) (*Provider, []erro
Name: fn.Name(),
Pos: fn.Pos(),
Args: make([]ProviderInput, params.Len()),
Varargs: sig.Variadic(),
Out: []types.Type{providerSig.out},
HasCleanup: providerSig.cleanup,
HasErr: providerSig.err,
Expand Down
31 changes: 31 additions & 0 deletions internal/wire/testdata/Varargs/foo/foo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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

import (
"fmt"
"strings"
)

func main() {
fmt.Println(injectedMessage("", "Hello,", "World!"))
}

type title string

// provideMessage provides a friendly user greeting.
func provideMessage(words ...string) string {
return strings.Join(words, " ")
}
26 changes: 26 additions & 0 deletions internal/wire/testdata/Varargs/foo/wire.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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 (
"github.com/google/wire"
)

func injectedMessage(t title, lines ...string) string {
wire.Build(provideMessage)
return ""
}
1 change: 1 addition & 0 deletions internal/wire/testdata/Varargs/pkg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
example.com/foo
1 change: 1 addition & 0 deletions internal/wire/testdata/Varargs/want/program_out.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello, World!
13 changes: 13 additions & 0 deletions internal/wire/testdata/Varargs/want/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 20 additions & 4 deletions internal/wire/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,12 @@ func (g *gen) inject(pos token.Pos, name string, sig *types.Signature, set *Prov
}

// Perform one pass to collect all imports, followed by the real pass.
injectPass(name, params, injectSig, calls, &injectorGen{
injectPass(name, sig, calls, &injectorGen{
g: g,
errVar: disambiguate("err", g.nameInFileScope),
discard: true,
})
injectPass(name, params, injectSig, calls, &injectorGen{
injectPass(name, sig, calls, &injectorGen{
g: g,
errVar: disambiguate("err", g.nameInFileScope),
discard: false,
Expand Down Expand Up @@ -551,7 +551,14 @@ type injectorGen struct {
}

// injectPass generates an injector given the output from analysis.
func injectPass(name string, params *types.Tuple, injectSig outputSignature, calls []call, ig *injectorGen) {
// The sig passed in should be verified.
func injectPass(name string, sig *types.Signature, calls []call, ig *injectorGen) {
params := sig.Params()
injectSig, err := funcOutput(sig)
if err != nil {
// This should be checked by the caller already.
panic(err)
}
ig.p("func %s(", name)
for i := 0; i < params.Len(); i++ {
if i > 0 {
Expand All @@ -565,7 +572,13 @@ func injectPass(name string, params *types.Tuple, injectSig outputSignature, cal
a = disambiguate(a, ig.nameInInjector)
}
ig.paramNames = append(ig.paramNames, a)
ig.p("%s %s", ig.paramNames[i], types.TypeString(pi.Type(), ig.g.qualifyPkg))
if sig.Variadic() && i == params.Len()-1 {
// Keep the varargs signature instead of a slice for the last argument if the
// injector is variadic.
ig.p("%s ...%s", ig.paramNames[i], types.TypeString(pi.Type().(*types.Slice).Elem(), ig.g.qualifyPkg))
} else {
ig.p("%s %s", ig.paramNames[i], types.TypeString(pi.Type(), ig.g.qualifyPkg))
}
}
outTypeString := types.TypeString(injectSig.out, ig.g.qualifyPkg)
switch {
Expand Down Expand Up @@ -639,6 +652,9 @@ func (ig *injectorGen) funcProviderCall(lname string, c *call, injectSig outputS
ig.p("%s", ig.localNames[a-len(ig.paramNames)])
}
}
if c.varargs {
ig.p("...")
}
ig.p(")\n")
if c.hasErr {
ig.p("\tif %s != nil {\n", ig.errVar)
Expand Down

0 comments on commit ef9bb67

Please sign in to comment.