diff --git a/internal/wire/analyze.go b/internal/wire/analyze.go index 32cf1196..d7f59abd 100644 --- a/internal/wire/analyze.go +++ b/internal/wire/analyze.go @@ -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 @@ -192,6 +195,7 @@ dfs: pkg: p.Pkg, name: p.Name, args: args, + varargs: p.Varargs, fieldNames: p.Fields, ins: ins, out: curr.t, diff --git a/internal/wire/parse.go b/internal/wire/parse.go index 8b57e280..75a7b190 100644 --- a/internal/wire/parse.go +++ b/internal/wire/parse.go @@ -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 @@ -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, diff --git a/internal/wire/testdata/Varargs/foo/foo.go b/internal/wire/testdata/Varargs/foo/foo.go new file mode 100644 index 00000000..d5a54140 --- /dev/null +++ b/internal/wire/testdata/Varargs/foo/foo.go @@ -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, " ") +} diff --git a/internal/wire/testdata/Varargs/foo/wire.go b/internal/wire/testdata/Varargs/foo/wire.go new file mode 100644 index 00000000..10211cc8 --- /dev/null +++ b/internal/wire/testdata/Varargs/foo/wire.go @@ -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 "" +} diff --git a/internal/wire/testdata/Varargs/pkg b/internal/wire/testdata/Varargs/pkg new file mode 100644 index 00000000..f7a5c8ce --- /dev/null +++ b/internal/wire/testdata/Varargs/pkg @@ -0,0 +1 @@ +example.com/foo diff --git a/internal/wire/testdata/Varargs/want/program_out.txt b/internal/wire/testdata/Varargs/want/program_out.txt new file mode 100644 index 00000000..8ab686ea --- /dev/null +++ b/internal/wire/testdata/Varargs/want/program_out.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/internal/wire/testdata/Varargs/want/wire_gen.go b/internal/wire/testdata/Varargs/want/wire_gen.go new file mode 100644 index 00000000..2ffaf3e8 --- /dev/null +++ b/internal/wire/testdata/Varargs/want/wire_gen.go @@ -0,0 +1,13 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate wire +//+build !wireinject + +package main + +// Injectors from wire.go: + +func injectedMessage(t title, lines ...string) string { + string2 := provideMessage(lines...) + return string2 +} diff --git a/internal/wire/wire.go b/internal/wire/wire.go index ef9ce687..656b067d 100644 --- a/internal/wire/wire.go +++ b/internal/wire/wire.go @@ -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, @@ -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 { @@ -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 { @@ -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)