error.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. // Copyright (c) 2019 Uber Technologies, Inc.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. package dig
  21. import (
  22. "errors"
  23. "fmt"
  24. "io"
  25. "reflect"
  26. "sort"
  27. "go.uber.org/dig/internal/digreflect"
  28. "go.uber.org/dig/internal/dot"
  29. )
  30. // Errors which know their underlying cause should implement this interface to
  31. // be compatible with RootCause.
  32. //
  33. // We use unexported methods because we don't want dig-internal causes to be
  34. // confused with the cause of the user-provided errors. For example, if we
  35. // used Unwrap(), then user-provided methods would also be unwrapped by
  36. // RootCause. We want RootCause to eliminate the dig error chain only.
  37. type causer interface {
  38. fmt.Formatter
  39. // Returns the next error in the chain.
  40. cause() error
  41. // Writes the message or context for this error in the chain.
  42. //
  43. // verb is either %v or %+v.
  44. writeMessage(w io.Writer, verb string)
  45. }
  46. // Implements fmt.Formatter for errors that implement causer.
  47. //
  48. // This Format method supports %v and %+v. In the %v form, the error is
  49. // printed on one line. In the %+v form, the error is split across multiple
  50. // lines on each error in the error chain.
  51. func formatCauser(c causer, w fmt.State, v rune) {
  52. multiline := w.Flag('+') && v == 'v'
  53. verb := "%v"
  54. if multiline {
  55. verb = "%+v"
  56. }
  57. // "context: " or "context:\n"
  58. c.writeMessage(w, verb)
  59. io.WriteString(w, ":")
  60. if multiline {
  61. io.WriteString(w, "\n")
  62. } else {
  63. io.WriteString(w, " ")
  64. }
  65. fmt.Fprintf(w, verb, c.cause())
  66. }
  67. // RootCause returns the original error that caused the provided dig failure.
  68. //
  69. // RootCause may be used on errors returned by Invoke to get the original
  70. // error returned by a constructor or invoked function.
  71. func RootCause(err error) error {
  72. for {
  73. if e, ok := err.(causer); ok {
  74. err = e.cause()
  75. } else {
  76. return err
  77. }
  78. }
  79. }
  80. // errf is a version of fmt.Errorf with support for a chain of multiple
  81. // formatted error messages.
  82. //
  83. // After msg, N arguments are consumed as formatting arguments for that
  84. // message, where N is the number of % symbols in msg. Following that, another
  85. // string may be added to become the next error in the chain. Each new error
  86. // is the `cause()` for the prior error.
  87. //
  88. // err := errf(
  89. // "could not process %v", thing,
  90. // "name %q is invalid", thing.Name,
  91. // )
  92. // fmt.Println(err) // could not process Thing: name Foo is invalid
  93. // fmt.Println(RootCause(err)) // name Foo is invalid
  94. //
  95. // In place of a string, the last error can be another error, in which case it
  96. // will be treated as the cause of the prior error chain.
  97. //
  98. // errf(
  99. // "could not process %v", thing,
  100. // "date %q could not be parsed", thing.Date,
  101. // parseError,
  102. // )
  103. func errf(msg string, args ...interface{}) error {
  104. // By implementing buildErrf as a closure rather than a standalone
  105. // function, we're able to ensure that it is called only from errf, or
  106. // from itself (recursively). By controlling these invocations in such
  107. // a tight space, we are able to easily verify manually that we
  108. // checked len(args) > 0 before making the call.
  109. var buildErrf func([]interface{}) error
  110. buildErrf = func(args []interface{}) error {
  111. arg, args := args[0], args[1:] // assume len(args) > 0
  112. if arg == nil {
  113. panic("It looks like you have found a bug in dig. " +
  114. "Please file an issue at https://github.com/uber-go/dig/issues/ " +
  115. "and provide the following message: " +
  116. "arg must not be nil")
  117. }
  118. switch v := arg.(type) {
  119. case string:
  120. need := numFmtArgs(v)
  121. if len(args) < need {
  122. panic(fmt.Sprintf(
  123. "It looks like you have found a bug in dig. "+
  124. "Please file an issue at https://github.com/uber-go/dig/issues/ "+
  125. "and provide the following message: "+
  126. "string %q needs %v arguments, got %v", v, need, len(args)))
  127. }
  128. msg := fmt.Sprintf(v, args[:need]...)
  129. args := args[need:]
  130. // If we don't have anything left to chain with, build the
  131. // final error.
  132. if len(args) == 0 {
  133. return errors.New(msg)
  134. }
  135. return wrappedError{
  136. msg: msg,
  137. err: buildErrf(args),
  138. }
  139. case error:
  140. if len(args) > 0 {
  141. panic(fmt.Sprintf(
  142. "It looks like you have found a bug in dig. "+
  143. "Please file an issue at https://github.com/uber-go/dig/issues/ "+
  144. "and provide the following message: "+
  145. "error must be the last element but got %v", args))
  146. }
  147. return v
  148. default:
  149. panic(fmt.Sprintf(
  150. "It looks like you have found a bug in dig. "+
  151. "Please file an issue at https://github.com/uber-go/dig/issues/ "+
  152. "and provide the following message: "+
  153. "unexpected errf-argument type %T", arg))
  154. }
  155. }
  156. // Prepend msg to the args list so that we can re-use the same
  157. // args processing logic. The msg is a string just for type-safety of
  158. // the first error.
  159. newArgs := make([]interface{}, len(args)+1)
  160. newArgs[0] = msg
  161. copy(newArgs[1:], args)
  162. return buildErrf(newArgs)
  163. }
  164. // Returns the number of formatting arguments in the provided string. Does not
  165. // count escaped % symbols, specifically the string "%%".
  166. //
  167. // fmt.Println(numFmtArgs("rate: %d%%")) // 1
  168. func numFmtArgs(s string) int {
  169. var (
  170. count int
  171. percent bool // saw %
  172. )
  173. for _, c := range s {
  174. if percent && c != '%' {
  175. // Counts only if it's not a %%.
  176. count++
  177. }
  178. // Next iteration should consider % only if the current %
  179. // stands alone.
  180. percent = !percent && c == '%'
  181. }
  182. return count
  183. }
  184. type wrappedError struct {
  185. err error
  186. msg string
  187. }
  188. var _ causer = wrappedError{}
  189. func (e wrappedError) cause() error {
  190. return e.err
  191. }
  192. func (e wrappedError) writeMessage(w io.Writer, _ string) {
  193. io.WriteString(w, e.msg)
  194. }
  195. func (e wrappedError) Error() string { return fmt.Sprint(e) }
  196. func (e wrappedError) Format(w fmt.State, c rune) {
  197. formatCauser(e, w, c)
  198. }
  199. // errProvide is returned when a constructor could not be Provided into the
  200. // container.
  201. type errProvide struct {
  202. Func *digreflect.Func
  203. Reason error
  204. }
  205. var _ causer = errProvide{}
  206. func (e errProvide) cause() error {
  207. return e.Reason
  208. }
  209. func (e errProvide) writeMessage(w io.Writer, verb string) {
  210. fmt.Fprintf(w, "cannot provide function "+verb, e.Func)
  211. }
  212. func (e errProvide) Error() string { return fmt.Sprint(e) }
  213. func (e errProvide) Format(w fmt.State, c rune) {
  214. formatCauser(e, w, c)
  215. }
  216. // errConstructorFailed is returned when a user-provided constructor failed
  217. // with a non-nil error.
  218. type errConstructorFailed struct {
  219. Func *digreflect.Func
  220. Reason error
  221. }
  222. var _ causer = errConstructorFailed{}
  223. func (e errConstructorFailed) cause() error {
  224. return e.Reason
  225. }
  226. func (e errConstructorFailed) writeMessage(w io.Writer, verb string) {
  227. fmt.Fprintf(w, "received non-nil error from function "+verb, e.Func)
  228. }
  229. func (e errConstructorFailed) Error() string { return fmt.Sprint(e) }
  230. func (e errConstructorFailed) Format(w fmt.State, c rune) {
  231. formatCauser(e, w, c)
  232. }
  233. // errArgumentsFailed is returned when a function could not be run because one
  234. // of its dependencies failed to build for any reason.
  235. type errArgumentsFailed struct {
  236. Func *digreflect.Func
  237. Reason error
  238. }
  239. var _ causer = errArgumentsFailed{}
  240. func (e errArgumentsFailed) cause() error {
  241. return e.Reason
  242. }
  243. func (e errArgumentsFailed) writeMessage(w io.Writer, verb string) {
  244. fmt.Fprintf(w, "could not build arguments for function "+verb, e.Func)
  245. }
  246. func (e errArgumentsFailed) Error() string { return fmt.Sprint(e) }
  247. func (e errArgumentsFailed) Format(w fmt.State, c rune) {
  248. formatCauser(e, w, c)
  249. }
  250. // errMissingDependencies is returned when the dependencies of a function are
  251. // not available in the container.
  252. type errMissingDependencies struct {
  253. Func *digreflect.Func
  254. Reason error
  255. }
  256. var _ causer = errMissingDependencies{}
  257. func (e errMissingDependencies) cause() error {
  258. return e.Reason
  259. }
  260. func (e errMissingDependencies) writeMessage(w io.Writer, verb string) {
  261. fmt.Fprintf(w, "missing dependencies for function "+verb, e.Func)
  262. }
  263. func (e errMissingDependencies) Error() string { return fmt.Sprint(e) }
  264. func (e errMissingDependencies) Format(w fmt.State, c rune) {
  265. formatCauser(e, w, c)
  266. }
  267. // errParamSingleFailed is returned when a paramSingle could not be built.
  268. type errParamSingleFailed struct {
  269. Key key
  270. Reason error
  271. CtorID dot.CtorID
  272. }
  273. var _ causer = errParamSingleFailed{}
  274. func (e errParamSingleFailed) cause() error {
  275. return e.Reason
  276. }
  277. func (e errParamSingleFailed) writeMessage(w io.Writer, _ string) {
  278. fmt.Fprintf(w, "failed to build %v", e.Key)
  279. }
  280. func (e errParamSingleFailed) Error() string { return fmt.Sprint(e) }
  281. func (e errParamSingleFailed) Format(w fmt.State, c rune) {
  282. formatCauser(e, w, c)
  283. }
  284. func (e errParamSingleFailed) updateGraph(g *dot.Graph) {
  285. failed := &dot.Result{
  286. Node: &dot.Node{
  287. Name: e.Key.name,
  288. Group: e.Key.group,
  289. Type: e.Key.t,
  290. },
  291. }
  292. g.FailNodes([]*dot.Result{failed}, e.CtorID)
  293. }
  294. // errParamGroupFailed is returned when a value group cannot be built because
  295. // any of the values in the group failed to build.
  296. type errParamGroupFailed struct {
  297. Key key
  298. Reason error
  299. CtorID dot.CtorID
  300. }
  301. var _ causer = errParamGroupFailed{}
  302. func (e errParamGroupFailed) cause() error {
  303. return e.Reason
  304. }
  305. func (e errParamGroupFailed) writeMessage(w io.Writer, _ string) {
  306. fmt.Fprintf(w, "could not build value group %v", e.Key)
  307. }
  308. func (e errParamGroupFailed) Error() string { return fmt.Sprint(e) }
  309. func (e errParamGroupFailed) Format(w fmt.State, c rune) {
  310. formatCauser(e, w, c)
  311. }
  312. func (e errParamGroupFailed) updateGraph(g *dot.Graph) {
  313. g.FailGroupNodes(e.Key.group, e.Key.t, e.CtorID)
  314. }
  315. // missingType holds information about a type that was missing in the
  316. // container.
  317. type missingType struct {
  318. Key key // item that was missing
  319. // If non-empty, we will include suggestions for what the user may have
  320. // meant.
  321. suggestions []key
  322. }
  323. // Format prints a string representation of missingType.
  324. //
  325. // With %v, it prints a short representation ideal for an itemized list.
  326. //
  327. // io.Writer
  328. // io.Writer: did you mean *bytes.Buffer?
  329. // io.Writer: did you mean *bytes.Buffer, or *os.File?
  330. //
  331. // With %+v, it prints a longer representation ideal for standalone output.
  332. //
  333. // io.Writer: did you mean to Provide it?
  334. // io.Writer: did you mean to use *bytes.Buffer?
  335. // io.Writer: did you mean to use one of *bytes.Buffer, or *os.File?
  336. func (mt missingType) Format(w fmt.State, v rune) {
  337. plusV := w.Flag('+') && v == 'v'
  338. fmt.Fprint(w, mt.Key)
  339. switch len(mt.suggestions) {
  340. case 0:
  341. if plusV {
  342. io.WriteString(w, " (did you mean to Provide it?)")
  343. }
  344. case 1:
  345. sug := mt.suggestions[0]
  346. if plusV {
  347. fmt.Fprintf(w, " (did you mean to use %v?)", sug)
  348. } else {
  349. fmt.Fprintf(w, " (did you mean %v?)", sug)
  350. }
  351. default:
  352. if plusV {
  353. io.WriteString(w, " (did you mean to use one of ")
  354. } else {
  355. io.WriteString(w, " (did you mean ")
  356. }
  357. lastIdx := len(mt.suggestions) - 1
  358. for i, sug := range mt.suggestions {
  359. if i > 0 {
  360. io.WriteString(w, ", ")
  361. if i == lastIdx {
  362. io.WriteString(w, "or ")
  363. }
  364. }
  365. fmt.Fprint(w, sug)
  366. }
  367. io.WriteString(w, "?)")
  368. }
  369. }
  370. // errMissingType is returned when one or more values that were expected in
  371. // the container were not available.
  372. //
  373. // Multiple instances of this error may be merged together by appending them.
  374. type errMissingTypes []missingType // inv: len > 0
  375. func newErrMissingTypes(c containerStore, k key) errMissingTypes {
  376. // Possible types we will look for in the container. We will always look
  377. // for pointers to the requested type and some extras on a per-Kind basis.
  378. suggestions := []reflect.Type{reflect.PtrTo(k.t)}
  379. if k.t.Kind() == reflect.Ptr {
  380. // The user requested a pointer but maybe we have a value.
  381. suggestions = append(suggestions, k.t.Elem())
  382. }
  383. knownTypes := c.knownTypes()
  384. if k.t.Kind() == reflect.Interface {
  385. // Maybe we have an implementation of the interface.
  386. for _, t := range knownTypes {
  387. if t.Implements(k.t) {
  388. suggestions = append(suggestions, t)
  389. }
  390. }
  391. } else {
  392. // Maybe we have an interface that this type implements.
  393. for _, t := range knownTypes {
  394. if t.Kind() == reflect.Interface {
  395. if k.t.Implements(t) {
  396. suggestions = append(suggestions, t)
  397. }
  398. }
  399. }
  400. }
  401. // range through c.providers is non-deterministic. Let's sort the list of
  402. // suggestions.
  403. sort.Sort(byTypeName(suggestions))
  404. mt := missingType{Key: k}
  405. for _, t := range suggestions {
  406. if len(c.getValueProviders(k.name, t)) > 0 {
  407. k.t = t
  408. mt.suggestions = append(mt.suggestions, k)
  409. }
  410. }
  411. return errMissingTypes{mt}
  412. }
  413. func (e errMissingTypes) Error() string {
  414. return fmt.Sprint(e)
  415. }
  416. func (e errMissingTypes) Format(w fmt.State, v rune) {
  417. multiline := w.Flag('+') && v == 'v'
  418. if len(e) == 1 {
  419. io.WriteString(w, "missing type:")
  420. } else {
  421. io.WriteString(w, "missing types:")
  422. }
  423. if !multiline {
  424. // With %v, we need a space between : since the error
  425. // won't be on a new line.
  426. io.WriteString(w, " ")
  427. }
  428. for i, mt := range e {
  429. if multiline {
  430. io.WriteString(w, "\n\t- ")
  431. } else if i > 0 {
  432. io.WriteString(w, "; ")
  433. }
  434. if multiline {
  435. fmt.Fprintf(w, "%+v", mt)
  436. } else {
  437. fmt.Fprintf(w, "%v", mt)
  438. }
  439. }
  440. }
  441. func (e errMissingTypes) updateGraph(g *dot.Graph) {
  442. missing := make([]*dot.Result, len(e))
  443. for i, mt := range e {
  444. missing[i] = &dot.Result{
  445. Node: &dot.Node{
  446. Name: mt.Key.name,
  447. Group: mt.Key.group,
  448. Type: mt.Key.t,
  449. },
  450. }
  451. }
  452. g.AddMissingNodes(missing)
  453. }
  454. type errVisualizer interface {
  455. updateGraph(*dot.Graph)
  456. }