Skip to content

errors.IsAny does not support multi-error #135

Description

@intercept6

It appears that errors.IsAny does not support multi-error.

funcIsAny(errerror, references...error) bool {
iferr==nil {
for_, refErr:=rangereferences {
ifrefErr==nil {
returntrue
}
}
// The mark-based comparison below will never match anything if
// the error is nil, so don't bother with computing the marks in
// that case. This avoids the computational expense of computing
// the reference marks upfront.
returnfalse
}
// First try using direct reference comparison.
forc:=err; c!=nil; c=errbase.UnwrapOnce(c) {
for_, refErr:=rangereferences {
ifrefErr==nil {
continue
}
isComparable:=reflect.TypeOf(refErr).Comparable()
ifisComparable&&c==refErr {
returntrue
}
// Compatibility with std go errors: if the error object itself
// implements Is(), try to use that.
iftryDelegateToIsMethod(c, refErr) {
returntrue
}
}
}
// Try harder with marks.
// Note: there is a more effective recursive algorithm that ensures
// that any pair of string only gets compared once. Should this
// become a performance bottleneck, that algorithm can be considered
// instead.
refMarks:=make([]errorMark, 0, len(references))
for_, refErr:=rangereferences {
ifrefErr==nil {
continue
}
refMarks=append(refMarks, getMark(refErr))
}
forc:=err; c!=nil; c=errbase.UnwrapOnce(c) {
errMark:=getMark(c)
for_, refMark:=rangerefMarks {
ifequalMarks(errMark, refMark) {
returntrue
}
}
}
returnfalse
}

errors.Is supports multi-error.

funcIs(err, referenceerror) bool {
ifreference==nil {
returnerr==nil
}
isComparable:=reflect.TypeOf(reference).Comparable()
// Direct reference comparison is the fastest, and most
// likely to be true, so do this first.
forc:=err; c!=nil; c=errbase.UnwrapOnce(c) {
ifisComparable&&c==reference {
returntrue
}
// Compatibility with std go errors: if the error object itself
// implements Is(), try to use that.
iftryDelegateToIsMethod(c, reference) {
returntrue
}
// Recursively try multi-error causes, if applicable.
for_, me:=rangeerrbase.UnwrapMulti(c) {
ifIs(me, reference) {
returntrue
}
}
}
iferr==nil {
// Err is nil and reference is non-nil, so it cannot match. We
// want to short-circuit the loop below in this case, otherwise
// we're paying the expense of getMark() without need.
returnfalse
}
// Not directly equal. Try harder, using error marks. We don't do
// this during the loop above as it may be more expensive.
//
// Note: there is a more effective recursive algorithm that ensures
// that any pair of string only gets compared once. Should the
// following code become a performance bottleneck, that algorithm
// can be considered instead.
refMark:=getMark(reference)
forc:=err; c!=nil; c=errbase.UnwrapOnce(c) {
ifequalMarks(getMark(c), refMark) {
returntrue
}
}
returnfalse
}

Perhaps the following equivalent code can be added to IsAny.

// Recursively try multi-error causes, if applicable. for_, me:=rangeerrbase.UnwrapMulti(c) { ifIs(me, reference) { returntrue } } 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions