From 6e864496af346a97518368cdbbb485c87867c06f Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Fri, 15 Dec 2023 19:41:36 +0530 Subject: [PATCH 1/8] feat: issue-185, write value directly without creating global variables --- internal/wire/wire.go | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/internal/wire/wire.go b/internal/wire/wire.go index 5cedeb1a..17fc3527 100644 --- a/internal/wire/wire.go +++ b/internal/wire/wire.go @@ -329,7 +329,6 @@ func (g *gen) inject(pos token.Pos, name string, sig *types.Signature, set *Prov expr ast.Expr typeInfo *types.Info } - var pendingVars []pendingVar ec := new(errorCollector) for i := range calls { c := &calls[i] @@ -354,15 +353,9 @@ func (g *gen) inject(pos token.Pos, name string, sig *types.Signature, set *Prov fmt.Errorf("inject %s: value %s can't be used: %v", name, ts, err))) } if g.values[c.valueExpr] == "" { - t := c.valueTypeInfo.TypeOf(c.valueExpr) - - name := typeVariableName(t, "", func(name string) string { return "_wire" + export(name) + "Value" }, g.nameInFileScope) - g.values[c.valueExpr] = name - pendingVars = append(pendingVars, pendingVar{ - name: name, - expr: c.valueExpr, - typeInfo: c.valueTypeInfo, - }) + var printValue strings.Builder + printer.Fprint(&printValue, g.pkg.Fset, g.rewritePkgRefs(c.valueTypeInfo, c.valueExpr)) + g.values[c.valueExpr] = printValue.String() } } } @@ -381,15 +374,6 @@ func (g *gen) inject(pos token.Pos, name string, sig *types.Signature, set *Prov errVar: disambiguate("err", g.nameInFileScope), discard: false, }) - if len(pendingVars) > 0 { - g.p("var (\n") - for _, pv := range pendingVars { - g.p("\t%s = ", pv.name) - g.writeAST(pv.typeInfo, pv.expr) - g.p("\n") - } - g.p(")\n\n") - } return nil } From c0c3a3b149e19e36e581d75f196cc7daa3553481 Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Fri, 15 Dec 2023 20:21:24 +0530 Subject: [PATCH 2/8] test CLA From db957ccda49f51a73c4f6831e122c5d77ad06aac Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Fri, 15 Dec 2023 22:02:16 +0530 Subject: [PATCH 3/8] fix: add gofmt changes and add CGO_ENABLED = 1 --- internal/runtests.sh | 2 +- wire.go | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/runtests.sh b/internal/runtests.sh index dd564732..90da83b6 100755 --- a/internal/runtests.sh +++ b/internal/runtests.sh @@ -26,7 +26,7 @@ fi result=0 if [[ "${RUNNER_OS:-}" == "Linux" ]]; then echo "Running Go tests (with coverage)..." - go test -mod=readonly -race -coverpkg=./... -coverprofile=coverage.out ./... || result=1 + go test -mod=readonly -race CGO_ENABLED=1 -coverpkg=./... -coverprofile=coverage.out ./... || result=1 if [ -f coverage.out ] && [ $result -eq 0 ]; then bash <(curl -s https://codecov.io/bash) fi diff --git a/wire.go b/wire.go index fe8edc8c..6af91dda 100644 --- a/wire.go +++ b/wire.go @@ -156,12 +156,12 @@ type StructProvider struct{} // // For example: // -// type S struct { -// MyFoo *Foo -// MyBar *Bar -// } -// var Set = wire.NewSet(wire.Struct(new(S), "MyFoo")) -> inject only S.MyFoo -// var Set = wire.NewSet(wire.Struct(new(S), "*")) -> inject all fields +// type S struct { +// MyFoo *Foo +// MyBar *Bar +// } +// var Set = wire.NewSet(wire.Struct(new(S), "MyFoo")) -> inject only S.MyFoo +// var Set = wire.NewSet(wire.Struct(new(S), "*")) -> inject all fields func Struct(structType interface{}, fieldNames ...string) StructProvider { return StructProvider{} } @@ -175,22 +175,22 @@ type StructFields struct{} // // The following example would provide Foo and Bar using S.MyFoo and S.MyBar respectively: // -// type S struct { -// MyFoo Foo -// MyBar Bar -// } +// type S struct { +// MyFoo Foo +// MyBar Bar +// } // -// func NewStruct() S { /* ... */ } -// var Set = wire.NewSet(wire.FieldsOf(new(S), "MyFoo", "MyBar")) +// func NewStruct() S { /* ... */ } +// var Set = wire.NewSet(wire.FieldsOf(new(S), "MyFoo", "MyBar")) // -// or +// or // -// func NewStruct() *S { /* ... */ } -// var Set = wire.NewSet(wire.FieldsOf(new(*S), "MyFoo", "MyBar")) +// func NewStruct() *S { /* ... */ } +// 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). +// 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 { return StructFields{} } From 02e526b89586405bd8fae66de65acbb5b0baf752 Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Fri, 15 Dec 2023 23:38:04 +0530 Subject: [PATCH 4/8] fix: test cases --- .../testdata/BindInterfaceWithValue/want/wire_gen.go | 6 +----- .../testdata/BuildTagsAllPackages/want/wire_gen.go | 6 +----- .../wire/testdata/ExampleWithMocks/want/wire_gen.go | 6 +----- .../wire/testdata/ExportedValue/want/wire_gen.go | 6 +----- .../ExportedValueDifferentPackage/want/wire_gen.go | 6 +----- .../testdata/FieldsOfValueStruct/want/wire_gen.go | 12 ++++-------- .../wire/testdata/InterfaceValue/want/wire_gen.go | 6 +----- internal/wire/testdata/NiladicValue/want/wire_gen.go | 6 +----- internal/wire/testdata/ValueChain/want/wire_gen.go | 6 +----- .../wire/testdata/ValueConversion/want/wire_gen.go | 6 +----- .../wire/testdata/ValueIsStruct/want/wire_gen.go | 6 +----- 11 files changed, 14 insertions(+), 58 deletions(-) diff --git a/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go b/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go index 58d82bf4..ac980cef 100644 --- a/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go +++ b/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go @@ -14,10 +14,6 @@ import ( // Injectors from wire.go: func inject() io.Writer { - file := _wireFileValue + file := os.Stdout return file } - -var ( - _wireFileValue = os.Stdout -) diff --git a/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go b/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go index 16c0df25..9c48a767 100644 --- a/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go +++ b/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go @@ -9,10 +9,6 @@ package main // Injectors from wire.go: func injectedMessage() string { - string2 := _wireStringValue + string2 := "Hello, World!" return string2 } - -var ( - _wireStringValue = "Hello, World!" -) diff --git a/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go b/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go index 9cb7b01c..559ece0f 100644 --- a/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go +++ b/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go @@ -10,7 +10,7 @@ package main // initApp returns a real app. func initApp() *app { - mainTimer := _wireRealTimeValue + mainTimer := realTime{} mainGreeter := greeter{ T: mainTimer, } @@ -20,10 +20,6 @@ func initApp() *app { return mainApp } -var ( - _wireRealTimeValue = realTime{} -) - // initMockedAppFromArgs returns an app with mocked dependencies provided via // arguments (Approach A). Note that the argument's type is the interface // type (timer), but the concrete mock type should be passed. diff --git a/internal/wire/testdata/ExportedValue/want/wire_gen.go b/internal/wire/testdata/ExportedValue/want/wire_gen.go index 7563ca26..62917353 100644 --- a/internal/wire/testdata/ExportedValue/want/wire_gen.go +++ b/internal/wire/testdata/ExportedValue/want/wire_gen.go @@ -13,10 +13,6 @@ import ( // Injectors from wire.go: func injectedMessage() string { - string2 := _wireStringValue + string2 := bar.PublicMsg return string2 } - -var ( - _wireStringValue = bar.PublicMsg -) diff --git a/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go b/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go index d8c74d4c..21809898 100644 --- a/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go +++ b/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go @@ -13,10 +13,6 @@ import ( // Injectors from wire.go: func injectedFile() *os.File { - file := _wireFileValue + file := os.Stdout return file } - -var ( - _wireFileValue = os.Stdout -) diff --git a/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go b/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go index 793c04d6..61322098 100644 --- a/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go +++ b/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go @@ -16,7 +16,10 @@ import ( // Injectors from wire.go: func newBazService() *baz.Service { - config := _wireConfigValue + config := &baz.Config{ + Foo: &foo.Config{1}, + Bar: &bar.Config{2}, + } fooConfig := config.Foo service := foo.New(fooConfig) barConfig := config.Bar @@ -28,13 +31,6 @@ func newBazService() *baz.Service { return bazService } -var ( - _wireConfigValue = &baz.Config{ - Foo: &foo.Config{1}, - Bar: &bar.Config{2}, - } -) - // wire.go: func main() { diff --git a/internal/wire/testdata/InterfaceValue/want/wire_gen.go b/internal/wire/testdata/InterfaceValue/want/wire_gen.go index 9868a902..5785ec62 100644 --- a/internal/wire/testdata/InterfaceValue/want/wire_gen.go +++ b/internal/wire/testdata/InterfaceValue/want/wire_gen.go @@ -14,10 +14,6 @@ import ( // Injectors from wire.go: func injectedReader() io.Reader { - reader := _wireReaderValue + reader := strings.NewReader("hello world") return reader } - -var ( - _wireReaderValue = strings.NewReader("hello world") -) diff --git a/internal/wire/testdata/NiladicValue/want/wire_gen.go b/internal/wire/testdata/NiladicValue/want/wire_gen.go index 16c0df25..9c48a767 100644 --- a/internal/wire/testdata/NiladicValue/want/wire_gen.go +++ b/internal/wire/testdata/NiladicValue/want/wire_gen.go @@ -9,10 +9,6 @@ package main // Injectors from wire.go: func injectedMessage() string { - string2 := _wireStringValue + string2 := "Hello, World!" return string2 } - -var ( - _wireStringValue = "Hello, World!" -) diff --git a/internal/wire/testdata/ValueChain/want/wire_gen.go b/internal/wire/testdata/ValueChain/want/wire_gen.go index da2cccb3..84bcab08 100644 --- a/internal/wire/testdata/ValueChain/want/wire_gen.go +++ b/internal/wire/testdata/ValueChain/want/wire_gen.go @@ -9,11 +9,7 @@ package main // Injectors from wire.go: func injectFooBar() FooBar { - foo := _wireFooValue + foo := Foo(41) fooBar := provideFooBar(foo) return fooBar } - -var ( - _wireFooValue = Foo(41) -) diff --git a/internal/wire/testdata/ValueConversion/want/wire_gen.go b/internal/wire/testdata/ValueConversion/want/wire_gen.go index b663861d..cd22f870 100644 --- a/internal/wire/testdata/ValueConversion/want/wire_gen.go +++ b/internal/wire/testdata/ValueConversion/want/wire_gen.go @@ -9,10 +9,6 @@ package main // Injectors from wire.go: func injectedMessage() Foo { - foo := _wireFooValue + foo := Foo("Hello, World!") return foo } - -var ( - _wireFooValue = Foo("Hello, World!") -) diff --git a/internal/wire/testdata/ValueIsStruct/want/wire_gen.go b/internal/wire/testdata/ValueIsStruct/want/wire_gen.go index f41ed122..af6da45e 100644 --- a/internal/wire/testdata/ValueIsStruct/want/wire_gen.go +++ b/internal/wire/testdata/ValueIsStruct/want/wire_gen.go @@ -9,10 +9,6 @@ package main // Injectors from wire.go: func injectFoo() Foo { - foo := _wireFooValue + foo := Foo{X: 42} return foo } - -var ( - _wireFooValue = Foo{X: 42} -) From 5a7bb4488c6183ae60f0aba903364daa5b2cf2ae Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Fri, 15 Dec 2023 23:38:43 +0530 Subject: [PATCH 5/8] revert runtests.sh changes --- internal/runtests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/runtests.sh b/internal/runtests.sh index 90da83b6..dd564732 100755 --- a/internal/runtests.sh +++ b/internal/runtests.sh @@ -26,7 +26,7 @@ fi result=0 if [[ "${RUNNER_OS:-}" == "Linux" ]]; then echo "Running Go tests (with coverage)..." - go test -mod=readonly -race CGO_ENABLED=1 -coverpkg=./... -coverprofile=coverage.out ./... || result=1 + go test -mod=readonly -race -coverpkg=./... -coverprofile=coverage.out ./... || result=1 if [ -f coverage.out ] && [ $result -eq 0 ]; then bash <(curl -s https://codecov.io/bash) fi From 42c63806d382e06874874a972bac687c546b5f5e Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Sat, 16 Dec 2023 11:57:52 +0530 Subject: [PATCH 6/8] fix: add backward compatibility by introducing wire.RawValue as an alternative injector --- internal/wire/analyze.go | 7 +- internal/wire/parse.go | 77 ++++++++++++++++--- .../BindInterfaceWithValue/want/wire_gen.go | 6 +- .../BuildTagsAllPackages/want/wire_gen.go | 6 +- .../ExampleWithMocks/want/wire_gen.go | 6 +- .../testdata/ExportedValue/want/wire_gen.go | 6 +- .../want/wire_gen.go | 6 +- .../FieldsOfValueStruct/want/wire_gen.go | 12 ++- .../testdata/InterfaceValue/want/wire_gen.go | 6 +- .../testdata/NiladicValue/want/wire_gen.go | 6 +- .../wire/testdata/ValueChain/want/wire_gen.go | 6 +- .../testdata/ValueConversion/want/wire_gen.go | 6 +- .../testdata/ValueIsStruct/want/wire_gen.go | 6 +- internal/wire/wire.go | 31 ++++++++ wire.go | 4 + 15 files changed, 165 insertions(+), 26 deletions(-) diff --git a/internal/wire/analyze.go b/internal/wire/analyze.go index 9650ef16..90777939 100644 --- a/internal/wire/analyze.go +++ b/internal/wire/analyze.go @@ -33,6 +33,7 @@ const ( structProvider valueExpr selectorExpr + rawValueExpr ) // A call represents a step of an injector function. It may be either a @@ -210,8 +211,12 @@ dfs: case pv.IsValue(): v := pv.Value() index.Set(curr.t, given.Len()+len(calls)) + valueExprKind := valueExpr + if pv.v.RawValue == true { + valueExprKind = rawValueExpr + } calls = append(calls, call{ - kind: valueExpr, + kind: valueExprKind, out: curr.t, valueExpr: v.expr, valueTypeInfo: v.info, diff --git a/internal/wire/parse.go b/internal/wire/parse.go index 93fbda85..e694b2ea 100644 --- a/internal/wire/parse.go +++ b/internal/wire/parse.go @@ -200,6 +200,8 @@ type Value struct { // info is the type info for the expression. info *types.Info + + RawValue bool } // InjectorArg describes a specific argument passed to an injector function. @@ -558,6 +560,12 @@ func (oc *objectCache) processExpr(info *types.Info, pkgPath string, expr ast.Ex return nil, []error{notePosition(exprPos, err)} } return v, nil + case "RawValue": + v, err := processRawValue(oc.fset, info, call) + if err != nil { + return nil, []error{notePosition(exprPos, err)} + } + return v, nil case "InterfaceValue": v, err := processInterfaceValue(oc.fset, info, call) if err != nil { @@ -964,10 +972,56 @@ func processValue(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*V return nil, notePosition(fset.Position(call.Pos()), fmt.Errorf("argument to Value may not be an interface value (found %s); use InterfaceValue instead", types.TypeString(argType, nil))) } return &Value{ - Pos: call.Args[0].Pos(), - Out: info.TypeOf(call.Args[0]), - expr: call.Args[0], - info: info, + Pos: call.Args[0].Pos(), + Out: info.TypeOf(call.Args[0]), + expr: call.Args[0], + info: info, + RawValue: false, + }, nil +} + +func processRawValue(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*Value, error) { + // Assumes that call.Fun is wire.Value. + + if len(call.Args) != 1 { + return nil, notePosition(fset.Position(call.Pos()), errors.New("call to Value takes exactly one argument")) + } + ok := true + ast.Inspect(call.Args[0], func(node ast.Node) bool { + switch expr := node.(type) { + case nil, *ast.ArrayType, *ast.BasicLit, *ast.BinaryExpr, *ast.ChanType, *ast.CompositeLit, *ast.FuncType, *ast.Ident, *ast.IndexExpr, *ast.InterfaceType, *ast.KeyValueExpr, *ast.MapType, *ast.ParenExpr, *ast.SelectorExpr, *ast.SliceExpr, *ast.StarExpr, *ast.StructType, *ast.TypeAssertExpr: + // Good! + case *ast.UnaryExpr: + if expr.Op == token.ARROW { + ok = false + return false + } + case *ast.CallExpr: + // Only acceptable if it's a type conversion. + if _, isFunc := info.TypeOf(expr.Fun).(*types.Signature); isFunc { + ok = false + return false + } + default: + ok = false + return false + } + return true + }) + if !ok { + return nil, notePosition(fset.Position(call.Pos()), errors.New("argument to Value is too complex")) + } + // Result type can't be an interface type; use wire.InterfaceValue for that. + argType := info.TypeOf(call.Args[0]) + if _, isInterfaceType := argType.Underlying().(*types.Interface); isInterfaceType { + return nil, notePosition(fset.Position(call.Pos()), fmt.Errorf("argument to Value may not be an interface value (found %s); use InterfaceValue instead", types.TypeString(argType, nil))) + } + return &Value{ + Pos: call.Args[0].Pos(), + Out: info.TypeOf(call.Args[0]), + expr: call.Args[0], + info: info, + RawValue: true, }, nil } @@ -993,10 +1047,11 @@ func processInterfaceValue(fset *token.FileSet, info *types.Info, call *ast.Call return nil, notePosition(fset.Position(call.Pos()), fmt.Errorf("%s does not implement %s", types.TypeString(provided, nil), types.TypeString(iface, nil))) } return &Value{ - Pos: call.Args[1].Pos(), - Out: iface, - expr: call.Args[1], - info: info, + Pos: call.Args[1].Pos(), + Out: iface, + expr: call.Args[1], + info: info, + RawValue: false, }, nil } @@ -1173,9 +1228,9 @@ func (pt ProvidedType) IsNil() bool { // // - 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. +// 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/want/wire_gen.go b/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go index ac980cef..58d82bf4 100644 --- a/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go +++ b/internal/wire/testdata/BindInterfaceWithValue/want/wire_gen.go @@ -14,6 +14,10 @@ import ( // Injectors from wire.go: func inject() io.Writer { - file := os.Stdout + file := _wireFileValue return file } + +var ( + _wireFileValue = os.Stdout +) diff --git a/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go b/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go index 9c48a767..16c0df25 100644 --- a/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go +++ b/internal/wire/testdata/BuildTagsAllPackages/want/wire_gen.go @@ -9,6 +9,10 @@ package main // Injectors from wire.go: func injectedMessage() string { - string2 := "Hello, World!" + string2 := _wireStringValue return string2 } + +var ( + _wireStringValue = "Hello, World!" +) diff --git a/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go b/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go index 559ece0f..9cb7b01c 100644 --- a/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go +++ b/internal/wire/testdata/ExampleWithMocks/want/wire_gen.go @@ -10,7 +10,7 @@ package main // initApp returns a real app. func initApp() *app { - mainTimer := realTime{} + mainTimer := _wireRealTimeValue mainGreeter := greeter{ T: mainTimer, } @@ -20,6 +20,10 @@ func initApp() *app { return mainApp } +var ( + _wireRealTimeValue = realTime{} +) + // initMockedAppFromArgs returns an app with mocked dependencies provided via // arguments (Approach A). Note that the argument's type is the interface // type (timer), but the concrete mock type should be passed. diff --git a/internal/wire/testdata/ExportedValue/want/wire_gen.go b/internal/wire/testdata/ExportedValue/want/wire_gen.go index 62917353..7563ca26 100644 --- a/internal/wire/testdata/ExportedValue/want/wire_gen.go +++ b/internal/wire/testdata/ExportedValue/want/wire_gen.go @@ -13,6 +13,10 @@ import ( // Injectors from wire.go: func injectedMessage() string { - string2 := bar.PublicMsg + string2 := _wireStringValue return string2 } + +var ( + _wireStringValue = bar.PublicMsg +) diff --git a/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go b/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go index 21809898..d8c74d4c 100644 --- a/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go +++ b/internal/wire/testdata/ExportedValueDifferentPackage/want/wire_gen.go @@ -13,6 +13,10 @@ import ( // Injectors from wire.go: func injectedFile() *os.File { - file := os.Stdout + file := _wireFileValue return file } + +var ( + _wireFileValue = os.Stdout +) diff --git a/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go b/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go index 61322098..793c04d6 100644 --- a/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go +++ b/internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go @@ -16,10 +16,7 @@ import ( // Injectors from wire.go: func newBazService() *baz.Service { - config := &baz.Config{ - Foo: &foo.Config{1}, - Bar: &bar.Config{2}, - } + config := _wireConfigValue fooConfig := config.Foo service := foo.New(fooConfig) barConfig := config.Bar @@ -31,6 +28,13 @@ func newBazService() *baz.Service { return bazService } +var ( + _wireConfigValue = &baz.Config{ + Foo: &foo.Config{1}, + Bar: &bar.Config{2}, + } +) + // wire.go: func main() { diff --git a/internal/wire/testdata/InterfaceValue/want/wire_gen.go b/internal/wire/testdata/InterfaceValue/want/wire_gen.go index 5785ec62..9868a902 100644 --- a/internal/wire/testdata/InterfaceValue/want/wire_gen.go +++ b/internal/wire/testdata/InterfaceValue/want/wire_gen.go @@ -14,6 +14,10 @@ import ( // Injectors from wire.go: func injectedReader() io.Reader { - reader := strings.NewReader("hello world") + reader := _wireReaderValue return reader } + +var ( + _wireReaderValue = strings.NewReader("hello world") +) diff --git a/internal/wire/testdata/NiladicValue/want/wire_gen.go b/internal/wire/testdata/NiladicValue/want/wire_gen.go index 9c48a767..16c0df25 100644 --- a/internal/wire/testdata/NiladicValue/want/wire_gen.go +++ b/internal/wire/testdata/NiladicValue/want/wire_gen.go @@ -9,6 +9,10 @@ package main // Injectors from wire.go: func injectedMessage() string { - string2 := "Hello, World!" + string2 := _wireStringValue return string2 } + +var ( + _wireStringValue = "Hello, World!" +) diff --git a/internal/wire/testdata/ValueChain/want/wire_gen.go b/internal/wire/testdata/ValueChain/want/wire_gen.go index 84bcab08..da2cccb3 100644 --- a/internal/wire/testdata/ValueChain/want/wire_gen.go +++ b/internal/wire/testdata/ValueChain/want/wire_gen.go @@ -9,7 +9,11 @@ package main // Injectors from wire.go: func injectFooBar() FooBar { - foo := Foo(41) + foo := _wireFooValue fooBar := provideFooBar(foo) return fooBar } + +var ( + _wireFooValue = Foo(41) +) diff --git a/internal/wire/testdata/ValueConversion/want/wire_gen.go b/internal/wire/testdata/ValueConversion/want/wire_gen.go index cd22f870..b663861d 100644 --- a/internal/wire/testdata/ValueConversion/want/wire_gen.go +++ b/internal/wire/testdata/ValueConversion/want/wire_gen.go @@ -9,6 +9,10 @@ package main // Injectors from wire.go: func injectedMessage() Foo { - foo := Foo("Hello, World!") + foo := _wireFooValue return foo } + +var ( + _wireFooValue = Foo("Hello, World!") +) diff --git a/internal/wire/testdata/ValueIsStruct/want/wire_gen.go b/internal/wire/testdata/ValueIsStruct/want/wire_gen.go index af6da45e..f41ed122 100644 --- a/internal/wire/testdata/ValueIsStruct/want/wire_gen.go +++ b/internal/wire/testdata/ValueIsStruct/want/wire_gen.go @@ -9,6 +9,10 @@ package main // Injectors from wire.go: func injectFoo() Foo { - foo := Foo{X: 42} + foo := _wireFooValue return foo } + +var ( + _wireFooValue = Foo{X: 42} +) diff --git a/internal/wire/wire.go b/internal/wire/wire.go index 17fc3527..484be923 100644 --- a/internal/wire/wire.go +++ b/internal/wire/wire.go @@ -329,6 +329,7 @@ func (g *gen) inject(pos token.Pos, name string, sig *types.Signature, set *Prov expr ast.Expr typeInfo *types.Info } + var pendingVars []pendingVar ec := new(errorCollector) for i := range calls { c := &calls[i] @@ -345,6 +346,25 @@ func (g *gen) inject(pos token.Pos, name string, sig *types.Signature, set *Prov fmt.Errorf("inject %s: provider for %s returns error but injection not allowed to fail", name, ts))) } if c.kind == valueExpr { + if err := accessibleFrom(c.valueTypeInfo, c.valueExpr, g.pkg.PkgPath); err != nil { + // TODO(light): Display line number of value expression. + ts := types.TypeString(c.out, nil) + ec.add(notePosition( + g.pkg.Fset.Position(pos), + fmt.Errorf("inject %s: value %s can't be used: %v", name, ts, err))) + } + if g.values[c.valueExpr] == "" { + t := c.valueTypeInfo.TypeOf(c.valueExpr) + + name := typeVariableName(t, "", func(name string) string { return "_wire" + export(name) + "Value" }, g.nameInFileScope) + g.values[c.valueExpr] = name + pendingVars = append(pendingVars, pendingVar{ + name: name, + expr: c.valueExpr, + typeInfo: c.valueTypeInfo, + }) + } + } else if c.kind == rawValueExpr { if err := accessibleFrom(c.valueTypeInfo, c.valueExpr, g.pkg.PkgPath); err != nil { // TODO(light): Display line number of value expression. ts := types.TypeString(c.out, nil) @@ -374,6 +394,15 @@ func (g *gen) inject(pos token.Pos, name string, sig *types.Signature, set *Prov errVar: disambiguate("err", g.nameInFileScope), discard: false, }) + if len(pendingVars) > 0 { + g.p("var (\n") + for _, pv := range pendingVars { + g.p("\t%s = ", pv.name) + g.writeAST(pv.typeInfo, pv.expr) + g.p("\n") + } + g.p(")\n\n") + } return nil } @@ -629,6 +658,8 @@ func injectPass(name string, sig *types.Signature, calls []call, set *ProviderSe ig.funcProviderCall(lname, c, injectSig) case valueExpr: ig.valueExpr(lname, c) + case rawValueExpr: + ig.valueExpr(lname, c) case selectorExpr: ig.fieldExpr(lname, c) default: diff --git a/wire.go b/wire.go index 6af91dda..5c522eb9 100644 --- a/wire.go +++ b/wire.go @@ -143,6 +143,10 @@ func InterfaceValue(typ interface{}, x interface{}) ProvidedValue { return ProvidedValue{} } +func RawValue(interface{}) ProvidedValue { + return ProvidedValue{} +} + // A StructProvider represents a named struct. type StructProvider struct{} From 46f9bdb028cccaf73cc8d9c23d812d58a775d82f Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Sat, 16 Dec 2023 12:05:34 +0530 Subject: [PATCH 7/8] fix: remove unwanted code formatting changes --- wire.go | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/wire.go b/wire.go index 5c522eb9..fe8edc8c 100644 --- a/wire.go +++ b/wire.go @@ -143,10 +143,6 @@ func InterfaceValue(typ interface{}, x interface{}) ProvidedValue { return ProvidedValue{} } -func RawValue(interface{}) ProvidedValue { - return ProvidedValue{} -} - // A StructProvider represents a named struct. type StructProvider struct{} @@ -160,12 +156,12 @@ type StructProvider struct{} // // For example: // -// type S struct { -// MyFoo *Foo -// MyBar *Bar -// } -// var Set = wire.NewSet(wire.Struct(new(S), "MyFoo")) -> inject only S.MyFoo -// var Set = wire.NewSet(wire.Struct(new(S), "*")) -> inject all fields +// type S struct { +// MyFoo *Foo +// MyBar *Bar +// } +// var Set = wire.NewSet(wire.Struct(new(S), "MyFoo")) -> inject only S.MyFoo +// var Set = wire.NewSet(wire.Struct(new(S), "*")) -> inject all fields func Struct(structType interface{}, fieldNames ...string) StructProvider { return StructProvider{} } @@ -179,22 +175,22 @@ type StructFields struct{} // // The following example would provide Foo and Bar using S.MyFoo and S.MyBar respectively: // -// type S struct { -// MyFoo Foo -// MyBar Bar -// } +// type S struct { +// MyFoo Foo +// MyBar Bar +// } // -// func NewStruct() S { /* ... */ } -// var Set = wire.NewSet(wire.FieldsOf(new(S), "MyFoo", "MyBar")) +// func NewStruct() S { /* ... */ } +// var Set = wire.NewSet(wire.FieldsOf(new(S), "MyFoo", "MyBar")) // -// or +// or // -// func NewStruct() *S { /* ... */ } -// var Set = wire.NewSet(wire.FieldsOf(new(*S), "MyFoo", "MyBar")) +// func NewStruct() *S { /* ... */ } +// 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). +// 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 { return StructFields{} } From 6dab424f6beec44b5e6bc4b2a4a57e5e02a1186b Mon Sep 17 00:00:00 2001 From: ProgrammingMuffin Date: Sat, 16 Dec 2023 12:06:27 +0530 Subject: [PATCH 8/8] fix: formatting --- wire.go | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/wire.go b/wire.go index fe8edc8c..5c522eb9 100644 --- a/wire.go +++ b/wire.go @@ -143,6 +143,10 @@ func InterfaceValue(typ interface{}, x interface{}) ProvidedValue { return ProvidedValue{} } +func RawValue(interface{}) ProvidedValue { + return ProvidedValue{} +} + // A StructProvider represents a named struct. type StructProvider struct{} @@ -156,12 +160,12 @@ type StructProvider struct{} // // For example: // -// type S struct { -// MyFoo *Foo -// MyBar *Bar -// } -// var Set = wire.NewSet(wire.Struct(new(S), "MyFoo")) -> inject only S.MyFoo -// var Set = wire.NewSet(wire.Struct(new(S), "*")) -> inject all fields +// type S struct { +// MyFoo *Foo +// MyBar *Bar +// } +// var Set = wire.NewSet(wire.Struct(new(S), "MyFoo")) -> inject only S.MyFoo +// var Set = wire.NewSet(wire.Struct(new(S), "*")) -> inject all fields func Struct(structType interface{}, fieldNames ...string) StructProvider { return StructProvider{} } @@ -175,22 +179,22 @@ type StructFields struct{} // // The following example would provide Foo and Bar using S.MyFoo and S.MyBar respectively: // -// type S struct { -// MyFoo Foo -// MyBar Bar -// } +// type S struct { +// MyFoo Foo +// MyBar Bar +// } // -// func NewStruct() S { /* ... */ } -// var Set = wire.NewSet(wire.FieldsOf(new(S), "MyFoo", "MyBar")) +// func NewStruct() S { /* ... */ } +// var Set = wire.NewSet(wire.FieldsOf(new(S), "MyFoo", "MyBar")) // -// or +// or // -// func NewStruct() *S { /* ... */ } -// var Set = wire.NewSet(wire.FieldsOf(new(*S), "MyFoo", "MyBar")) +// func NewStruct() *S { /* ... */ } +// 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). +// 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 { return StructFields{} }