diff --git a/internal/handler/handler.go b/internal/handler/handler.go index e80300d..98e3831 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -74,6 +74,21 @@ func NilNoop(err error) error { return err } // func ErrorNoop(err error) {} +// initErrors initializes both i.Err and i.werr with a new error pointer. +// Used by PreProcess for setting up error handling with a local error variable. +func (i *Info) initErrors(errPtr *error) { + i.Err = errPtr + i.werr = *errPtr +} + +// setErrors updates both *i.Err and i.werr to keep them in sync. +// Assumes i.Err is already initialized (non-nil pointer). +// Used by error handlers to update the error value. +func (i *Info) setErrors(err error) { + *i.Err = err + i.werr = err +} + func (i *Info) callNilHandler() { if i.CheckHandler != nil && i.safeErr() == nil { i.CheckHandler(true) @@ -86,8 +101,8 @@ func (i *Info) callNilHandler() { i.checkErrorTracer() } if i.NilFn != nil { - *i.Err = i.NilFn(i.werr) - i.werr = *i.Err // remember change both our errors! + result := i.NilFn(i.werr) + i.setErrors(result) } else { i.defaultNilHandler() } @@ -120,14 +135,16 @@ func (i *Info) callErrorHandler() { if i.ErrorFn != nil { // we want to auto-annotate error first and exec ErrorFn then i.werr = i.workError() + var result error + if i.needErrorAnnotation && i.werr != nil { i.buildFmtErr() - *i.Err = i.ErrorFn(*i.Err) + result = i.ErrorFn(*i.Err) } else { - *i.Err = i.ErrorFn(i.Any.(error)) + result = i.ErrorFn(i.Any.(error)) } - i.werr = *i.Err // remember change both our errors! + i.setErrors(result) } else { i.defaultErrorHandler() } @@ -165,8 +182,8 @@ func (i *Info) workError() (err error) { } func (i *Info) fmtErr() { - *i.Err = fmt.Errorf(i.Format+i.wrapStr(), append(i.Args, i.werr)...) - i.werr = *i.Err // remember change both our errors! + result := fmt.Errorf(i.Format+i.wrapStr(), append(i.Args, i.werr)...) + i.setErrors(result) } func (i *Info) buildFmtErr() { @@ -279,11 +296,10 @@ func Process(info *Info) { func PreProcess(errPtr *error, info *Info, a []any) error { // Bug in Go? // start to use local error ptr only for optimization reasons. - // We get 3x faster defer handlers without unsing ptr to original err + // We get 3x faster defer handlers without using ptr to original err // named return val. Reason is unknown. err := x.Whom(errPtr != nil, *errPtr, nil) - info.Err = &err - info.werr = *info.Err // remember change both our errors! + info.initErrors(&err) // We want the function who sets the handler, i.e. calls the // err2.Handle function via defer. Because call stack is in reverse @@ -312,9 +328,12 @@ func PreProcess(errPtr *error, info *Info, a []any) error { const framesToSkip = 6 frame = x.Whom(ok, frame, framesToSkip) if LogOutput(frame, curErr.Error()) == nil { - *info.Err = nil // prevent dublicate "logging" + *info.Err = nil // prevent duplicate "logging" } } + + // Note: Since info.Err points to &err, any updates to *info.Err will also update err. + // Therefore, we can return the local err variable which reflects the final processed state. return err }