From adfd77edc4cbb9dc1f00682b246b6d8424ac2c8f Mon Sep 17 00:00:00 2001 From: Kian Parvin Date: Thu, 22 Oct 2026 15:20:51 +0200 Subject: [PATCH] fix: use stderrors AsType and bump to Go 1.26 --- functions.go | 38 ++------------- functions_test.go | 115 +++++++--------------------------------------- go.mod | 2 +- 3 files changed, 20 insertions(+), 135 deletions(-) diff --git a/functions.go b/functions.go index 952a6739..48f02275 100644 --- a/functions.go +++ b/functions.go @@ -370,42 +370,10 @@ func As(err error, target interface{}) bool { return stderrors.As(err, target) } -// AsType is a convenience method for checking and getting an error from within -// a chain that is of type T. If no error is found of type T in the chain the -// zero value of T is returned with false. If an error in the chain implementes -// As(any) bool then it's As method will be called if it's type is not of type T. - -// AsType finds the first error in err's chain that is assignable to type T, and -// if a match is found, returns that error value and true. Otherwise, it returns -// T's zero value and false. -// -// AsType is equivalent to errors.As, but uses a type parameter and returns -// the target, to avoid having to define a variable before the call. For -// example, callers can replace this: -// -// var pathError *fs.PathError -// if errors.As(err, &pathError) { -// fmt.Println("Failed at path:", pathError.Path) -// } -// -// With: -// -// if pathError, ok := errors.AsType[*fs.PathError](err); ok { -// fmt.Println("Failed at path:", pathError.Path) -// } +// AsType is a proxy for the AsType function in Go's standard `errors` library +// (pkg.go.dev/errors). It finds the first error in err's tree that matches T. func AsType[T error](err error) (T, bool) { - for err != nil { - if e, is := err.(T); is { - return e, true - } - var res T - if x, ok := err.(interface{ As(any) bool }); ok && x.As(&res) { - return res, true - } - err = stderrors.Unwrap(err) - } - var zero T - return zero, false + return stderrors.AsType[T](err) } // SetLocation takes a given error and records where in the stack SetLocation diff --git a/functions_test.go b/functions_test.go index 9f1a11aa..8a043687 100644 --- a/functions_test.go +++ b/functions_test.go @@ -360,6 +360,22 @@ func (*functionSuite) TestAs(c *gc.C) { } } +func (*functionSuite) TestAsType(c *gc.C) { + baseError := &basicError{"I'm an error"} + testErrors := []error{ + errors.Trace(baseError), + errors.Annotate(baseError, "annotation"), + errors.Wrap(baseError, errors.New("wrapper")), + errors.Mask(baseError), + } + + for _, err := range testErrors { + bError, val := errors.AsType[*basicError](err) + c.Check(val, gc.Equals, true) + c.Check(bError.Reason, gc.Equals, "I'm an error") + } +} + func (*functionSuite) TestIs(c *gc.C) { baseError := &basicError{"I'm an error"} testErrors := []error{ @@ -403,105 +419,6 @@ func (*functionSuite) TestQuietWrappedErrorStillSatisfied(c *gc.C) { c.Assert(errors.Is(err, simpleTestError), gc.Equals, true) } -type ComplexErrorMessage interface { - error - ComplexMessage() string -} - -type complexError struct { - Message string -} - -func (c *complexError) Error() string { - return c.Message -} - -func (c *complexError) ComplexMessage() string { - return c.Message -} - -type complexErrorOther struct { - Message string -} - -func (c *complexErrorOther) As(e any) bool { - if ce, ok := e.(**complexError); ok { - *ce = &complexError{ - Message: c.Message, - } - return true - } - return false -} - -func (c *complexErrorOther) Error() string { - return c.Message -} - -func (c *complexErrorOther) ComplexMessage() string { - return c.Message -} - -func (*functionSuite) TestHasType(c *gc.C) { - complexErr := &complexError{Message: "complex error message"} - wrapped1 := fmt.Errorf("wrapping1: %w", complexErr) - wrapped2 := fmt.Errorf("wrapping2: %w", wrapped1) - - c.Assert(errors.HasType[*complexError](complexErr), gc.Equals, true) - c.Assert(errors.HasType[*complexError](wrapped1), gc.Equals, true) - c.Assert(errors.HasType[*complexError](wrapped2), gc.Equals, true) - c.Assert(errors.HasType[ComplexErrorMessage](wrapped2), gc.Equals, true) - c.Assert(errors.HasType[*complexErrorOther](wrapped2), gc.Equals, false) - c.Assert(errors.HasType[*complexErrorOther](nil), gc.Equals, false) - - complexErrOther := &complexErrorOther{Message: "another complex error"} - - c.Assert(errors.HasType[*complexError](complexErrOther), gc.Equals, true) - - wrapped2 = fmt.Errorf("wrapping1: %w", complexErrOther) - c.Assert(errors.HasType[*complexError](wrapped2), gc.Equals, true) -} - -func (*functionSuite) TestAsType(c *gc.C) { - complexErr := &complexError{Message: "complex error message"} - wrapped1 := fmt.Errorf("wrapping1: %w", complexErr) - wrapped2 := fmt.Errorf("wrapping2: %w", wrapped1) - - ce, ok := errors.AsType[*complexError](complexErr) - c.Assert(ok, gc.Equals, true) - c.Assert(ce.Message, gc.Equals, complexErr.Message) - - ce, ok = errors.AsType[*complexError](wrapped1) - c.Assert(ok, gc.Equals, true) - c.Assert(ce.Message, gc.Equals, complexErr.Message) - - ce, ok = errors.AsType[*complexError](wrapped2) - c.Assert(ok, gc.Equals, true) - c.Assert(ce.Message, gc.Equals, complexErr.Message) - - cem, ok := errors.AsType[ComplexErrorMessage](wrapped2) - c.Assert(ok, gc.Equals, true) - c.Assert(cem.ComplexMessage(), gc.Equals, complexErr.Message) - - ceo, ok := errors.AsType[*complexErrorOther](wrapped2) - c.Assert(ok, gc.Equals, false) - c.Assert(ceo, gc.Equals, (*complexErrorOther)(nil)) - - ceo, ok = errors.AsType[*complexErrorOther](nil) - c.Assert(ok, gc.Equals, false) - c.Assert(ceo, gc.Equals, (*complexErrorOther)(nil)) - - complexErrOther := &complexErrorOther{Message: "another complex error"} - ce, ok = errors.AsType[*complexError](complexErrOther) - c.Assert(ok, gc.Equals, true) - c.Assert(ce.Message, gc.Equals, complexErrOther.Message) - - wrapped2 = fmt.Errorf("wrapping1: %w", complexErrOther) - ce, ok = errors.AsType[*complexError](wrapped2) - c.Assert(ok, gc.Equals, true) - c.Assert(ce.Message, gc.Equals, complexErrOther.Message) -} - func ExampleHide() { myConstError := errors.ConstError("I don't want to be fmt printed") err := fmt.Errorf("don't show this error%w", errors.Hide(myConstError)) diff --git a/go.mod b/go.mod index 76c393d3..c274441c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/juju/errors -go 1.18 +go 1.26 require gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c