Repository: uber-go/fx
Pull request #844 (2022-02-18 20:12:05)

Make provide's errors more expressive for fx.Annotate-ed functions
Because of the use of reflection in fx.Annotate, the error
messages for provide tend to refer to the annotated function as
`"reflect".makeFuncStub` which is not helpful for debugging.

This change updates error messages that previously looked like:
```
Failed: cannot provide function "reflect".makeFuncStub (/usr/local/go/src/reflect/asm_arm64.s:12):
cannot provide *fx_test.Logger from [0].Field0: already provided by "reflect".makeFuncStub
(/usr/local/go/src/reflect/asm_arm64.s:12)
```

To looking like this:
```
Failed: cannot provide function "reflect".makeFuncStub (/usr/local/go/src/reflect/asm_amd64.s:12):
cannot provide *fx_test.Logger from [0].Field0: already provided by "go.uber.org/fx_test".TestAnnotate.func1
(/gocode/src/github.com/uber-go/fx/annotated_test.go:515)
```

WIP: Planning on making a future fix that gives a more
readable name to the first function which still is referred to
as "reflect".makeFuncStub after this change.

codecov[bot]: # [Codecov](https://codecov.io/gh/uber-go/fx/pull/844?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) Report
> Merging [#844](https://codecov.io/gh/uber-go/fx/pull/844?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) (412e0c7) into [master](https://codecov.io/gh/uber-go/fx/commit/9173ccdc0e99ac9929831e8435b93501310d10cf?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) (9173ccd) will **decrease** coverage by `0.18%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/uber-go/fx/pull/844/graphs/tree.svg?width=650&height=150&src=pr&token=PYY9PSfaC6&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go)](https://codecov.io/gh/uber-go/fx/pull/844?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go)

```diff
@@            Coverage Diff             @@
##           master     #844      +/-   ##
==========================================
- Coverage   98.56%   98.37%   -0.19%     
==========================================
  Files          29       29              
  Lines        1043     1045       +2     
==========================================
  Hits         1028     1028              
- Misses         10       11       +1     
- Partials        5        6       +1     
```


| [Impacted Files](https://codecov.io/gh/uber-go/fx/pull/844?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) | Coverage Δ | |
|---|---|---|
| [annotated.go](https://codecov.io/gh/uber-go/fx/pull/844/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go#diff-YW5ub3RhdGVkLmdv) | `99.39% <100.00%> (+<0.01%)` | :arrow_up: |
| [provide.go](https://codecov.io/gh/uber-go/fx/pull/844/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go#diff-cHJvdmlkZS5nbw==) | `100.00% <100.00%> (ø)` | |
| [app.go](https://codecov.io/gh/uber-go/fx/pull/844/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go#diff-YXBwLmdv) | `94.95% <0.00%> (-0.92%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/uber-go/fx/pull/844?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/uber-go/fx/pull/844?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go). Last update [9173ccd...412e0c7](https://codecov.io/gh/uber-go/fx/pull/844?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go).


Patch:
diff --git a/annotated.go b/annotated.go
index 06a15ff..85a8ec0 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/provide.go b/provide.go
index 52b01e3..c37b8c0 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)
 		}


Test patch:
diff --git a/annotated_test.go b/annotated_test.go
index 19bed2c..f8ba3b9 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()