diff --git a/annotated.go b/annotated.go index 06a15fff2..85a8ec0e6 100644 --- a/annotated.go +++ b/annotated.go @@ -264,6 +264,7 @@ type annotated struct { ParamTags []string ResultTags []string As [][]reflect.Type + FuncPtr uintptr } func (ann annotated) String() string { @@ -302,6 +303,7 @@ func (ann *annotated) Build() (interface{}, error) { newFnType := reflect.FuncOf(paramTypes, resultTypes, false) origFn := reflect.ValueOf(ann.Target) + ann.FuncPtr = origFn.Pointer() newFn := reflect.MakeFunc(newFnType, func(args []reflect.Value) []reflect.Value { args = remapParams(args) var results []reflect.Value diff --git a/annotated_test.go b/annotated_test.go index 19bed2caf..f8ba3b9e1 100644 --- a/annotated_test.go +++ b/annotated_test.go @@ -787,6 +787,22 @@ func TestAnnotate(t *testing.T) { defer app.RequireStart().RequireStop() }) + t.Run("provide an already provided function using Annotate", func(t *testing.T) { + t.Parallel() + + app := NewForTest(t, + fx.Provide(fx.Annotate(newA, fx.ResultTags(`name:"a"`))), + fx.Provide(fx.Annotate(newA, fx.ResultTags(`name:"a"`))), + fx.Invoke( + fx.Annotate(newB, fx.ParamTags(`name:"a"`)), + ), + ) + err := app.Err() + require.Error(t, err) + assert.Contains(t, err.Error(), "already provided") + assert.Contains(t, err.Error(), "\"go.uber.org/fx_test\".TestAnnotate.func1") + }) + t.Run("specify more ParamTags than Params", func(t *testing.T) { t.Parallel() diff --git a/provide.go b/provide.go index 52b01e317..c37b8c0bc 100644 --- a/provide.go +++ b/provide.go @@ -109,6 +109,7 @@ func runProvide(c container, p provide, opts ...dig.ProvideOption) error { return fmt.Errorf("fx.Provide(%v) from:\n%+vFailed: %v", constructor, p.Stack, err) } + opts = append(opts, dig.LocationForPC(constructor.FuncPtr)) if err := c.Provide(ctor, opts...); err != nil { return fmt.Errorf("fx.Provide(%v) from:\n%+vFailed: %v", constructor, p.Stack, err) }