Skip to content

Fix identified linter errors preventing errorlint, exhaustive, inamedparam, and staticcheck from running and enable those checks. #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a87035b
Fix some small issues that were flagged by upcoming lint checks.
rsned Apr 2, 2025
ed507ae
replace the swap edges, newEdges which left a dangling value with _
rsned Apr 2, 2025
39caea7
Add todo on this //nolint.
rsned Apr 2, 2025
69704c9
Add linter/formatter/govet github action.
rsned Apr 2, 2025
12554af
Merge branch 'golang:master' into master
rsned Apr 3, 2025
55902bd
Fix OSSF detected go.mod toolchain version issue.
rsned Apr 3, 2025
4f7483f
update to use git hashes instead of @v5 style.
rsned Apr 4, 2025
e141dbf
Use dependabot compatible version comments
alan-strohm Apr 4, 2025
c597829
Add comments on disabled checks. Add a few more entries.
rsned Apr 8, 2025
5836f6f
Merge branch 'golang:master' into master
rsned Apr 8, 2025
7c7e52c
Merge remote-tracking branch 'refs/remotes/origin/master'
rsned Apr 8, 2025
6df2625
Update some comments and add in reference to related issue number for…
rsned Apr 8, 2025
0f45e9d
Remove govet from enabled. Drop exclusions. Clarify some comments.
rsned Apr 8, 2025
6937d18
Fix some typos
alan-strohm Apr 9, 2025
aeac25e
Set gofmt formatter to keep the default -s (simplify option)
rsned Apr 10, 2025
6570bb0
Re-disable simplify until existing files are fixed.
rsned Apr 10, 2025
46b2465
Update permissions to read-all
rsned Apr 10, 2025
ddcf335
Fix errors that were blocking 'errorlint' checks.
rsned Apr 10, 2025
97c005f
Enable errorlint and exhaustive checks.
rsned Apr 10, 2025
b0a75d1
Add nolint comment tags to the cases tripping exhaustive.
rsned Apr 10, 2025
b490ab9
Fix code that trips inamedparam checks.
rsned Apr 10, 2025
d52dbd3
Fix r3 with nolint comment for exhaustive checks.
rsned Apr 10, 2025
c350037
Enable inamedparam check.
rsned Apr 10, 2025
d9b9b57
Merge branch 'golang:master' into lint
rsned Apr 10, 2025
c6c66f3
Resolve the outstanding staticcheck lint errors.
rsned Apr 10, 2025
ee8b694
Merge remote-tracking branch 'refs/remotes/origin/lint' into lint
rsned Apr 11, 2025
82699bd
Remove staticcheck from disabled checks.
rsned Apr 14, 2025
05c557d
Merge branch 'golang:master' into lint
rsned Apr 14, 2025
d2d1712
Merge branch 'master' into lint
rsned Apr 14, 2025
d057b73
nit: Use `r` as parameter name for io.Reader.
alan-strohm Apr 16, 2025
13cc0cd
.golangci.yml: remove some obsolete comments
alan-strohm Apr 16, 2025
6039c41
Update vector.go to explicitly enumerate all switch cases instead of …
rsned Apr 16, 2025
b55b55a
Update point.go to explicitly use all three switch cases and remove n…
rsned Apr 16, 2025
809fb29
Update stuv_test.go to explicitly use all three switch cases and rem…
rsned Apr 16, 2025
a917062
Update edge_crossings.go to explicitly use all three switch cases an…
rsned Apr 16, 2025
4e3cd3f
Update edge_crossings.go
rsned Apr 16, 2025
0c1ec02
Fix the final two exhaustive lint check cases with nolint tags.
rsned Apr 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ linters:
# Commented entries here are not enabled by default, but that we should
# add once the relevant lines are fixed up.

# - errorlint # found 2 cases to be fixed.
# - exhaustive # found some cases that should be fixed.
- errorlint
- exhaustive
# - exhaustruct # found some structs which missed fields in initializing.
# - inamedparam # fix missing named param
- inamedparam
# - makezero # fix the unallocated elements.
# - misspell # fix spelling
# - nlreturn # fix these missing blank line
Expand Down Expand Up @@ -68,8 +68,6 @@ linters:
# Triggers on most tests for failing to call paralleltest.
# We don't have a need to use this so keep it disabled.
- paralleltest
# Enable once outstanding lint bugs are fixed.
- staticcheck
# This triggers on every _test file saying they should be separate
# parallel packages e.g. s2->s2_test package. We do not plan to ever
# reshuffle the tests into a separate package.
Expand Down
2 changes: 1 addition & 1 deletion r3/vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (v Vector) Ortho() Vector {
ov.Z = 1
case YAxis:
ov.X = 1
default:
case ZAxis:
ov.Y = 1
}
return v.Cross(ov).Normalize()
Expand Down
4 changes: 2 additions & 2 deletions s2/cap.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func FullCap() Cap {

// IsValid reports whether the Cap is considered valid.
func (c Cap) IsValid() bool {
return c.center.Vector.IsUnit() && c.radius <= s1.StraightChordAngle
return c.center.IsUnit() && c.radius <= s1.StraightChordAngle
}

// IsEmpty reports whether the cap is empty, i.e. it contains no points.
Expand Down Expand Up @@ -391,7 +391,7 @@ func (c Cap) intersects(cell Cell, vertices [4]Point) bool {
sin2Angle := c.radius.Sin2()
for k := 0; k < 4; k++ {
edge := cell.Edge(k).Vector
dot := c.center.Vector.Dot(edge)
dot := c.center.Dot(edge)
if dot > 0 {
// The center is in the interior half-space defined by the edge. We do not need
// to consider these edges, since if the cap intersects this edge then it also
Expand Down
6 changes: 3 additions & 3 deletions s2/cap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ func TestCapContainsCell(t *testing.T) {
if got, want := covering.ContainsCell(rootCell), capFace == face; got != want {
t.Errorf("Cap(%v).ContainsCell(%v) = %t; want = %t", covering, rootCell, got, want)
}
if got, want := covering.ContainsCell(edgeCell), center.Vector.Dot(edgeCell.id.Point().Vector) > 0.1; got != want {
if got, want := covering.ContainsCell(edgeCell), center.Dot(edgeCell.id.Point().Vector) > 0.1; got != want {
t.Errorf("Cap(%v).ContainsCell(%v) = %t; want = %t", covering, edgeCell, got, want)
}
if got, want := covering.ContainsCell(edgeCell), covering.IntersectsCell(edgeCell); got != want {
Expand Down Expand Up @@ -552,7 +552,7 @@ func TestCapIntersectsCell(t *testing.T) {
if got, want := covering.IntersectsCell(edgeCell), covering.ContainsCell(edgeCell); got != want {
t.Errorf("Cap(%v).IntersectsCell(%v) = %t; want = %t", covering, edgeCell, got, want)
}
if got, want := covering.IntersectsCell(cornerCell), center.Vector.Dot(cornerCell.id.Point().Vector) > 0; got != want {
if got, want := covering.IntersectsCell(cornerCell), center.Dot(cornerCell.id.Point().Vector) > 0; got != want {
t.Errorf("Cap(%v).IntersectsCell(%v) = %t; want = %t", covering, cornerCell, got, want)
}

Expand All @@ -561,7 +561,7 @@ func TestCapIntersectsCell(t *testing.T) {
if got, want := bulging.IntersectsCell(rootCell), capFace != antiFace; got != want {
t.Errorf("Cap(%v).IntersectsCell(%v) = %t; want = %t", bulging, rootCell, got, want)
}
if got, want := bulging.IntersectsCell(edgeCell), center.Vector.Dot(edgeCell.id.Point().Vector) > 0.1; got != want {
if got, want := bulging.IntersectsCell(edgeCell), center.Dot(edgeCell.id.Point().Vector) > 0.1; got != want {
t.Errorf("Cap(%v).IntersectsCell(%v) = %t; want = %t", bulging, edgeCell, got, want)
}
if bulging.IntersectsCell(cornerCell) {
Expand Down
2 changes: 1 addition & 1 deletion s2/cell_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func verifyCellIndexRangeIterators(t *testing.T, desc string, index *CellIndex)
if start != it2.StartID() {
t.Errorf("%s: it2.StartID() = %v, want %v", desc, it2.StartID(), start)
}
if 0 != prevStart {
if prevStart != 0 {
t.Errorf("%s: prevStart = %v, want %v", desc, prevStart, 0)
}
}
Expand Down
2 changes: 1 addition & 1 deletion s2/cellid.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ func CellIDFromString(s string) CellID {
}
id := CellIDFromFace(face)
for i := 2; i < len(s); i++ {
var childPos byte = s[i] - '0'
var childPos = s[i] - '0'
// Bytes are non-negative.
if childPos > 3 {
return CellID(0)
Expand Down
2 changes: 1 addition & 1 deletion s2/cellunion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ func TestCellUnionFromUnionDiffIntersection(t *testing.T) {
u := CellUnionFromIntersectionWithCellID(xcells, yid)
for _, xid := range xcells {
if xid.Contains(yid) {
if !(len(u) == 1 && u[0] == yid) {
if !(len(u) == 1 && u[0] == yid) { // nolint staticcheck - DeMorgan's doesn't work here.
t.Errorf("CellUnionFromIntersectionWithCellID(%v, %v) = %v with len: %d, want len of 1.", xcells, yid, u, len(u))
}
} else if yid.Contains(xid) {
Expand Down
14 changes: 9 additions & 5 deletions s2/crossing_edge_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,16 +277,20 @@ func (c *CrossingEdgeQuery) getCellsForEdge(a, b Point) {
// 3. edgeRoot does not intersect any index cells. In this case there
// is nothing to do.
relation := c.iter.LocateCellID(edgeRoot)
if relation == Indexed {
// edgeRoot is an index cell or is contained by an index cell (case 1).
switch relation {
case Indexed:
// edgeRoot is an index cell or is contained by an
// index cell (case 1).
c.cells = append(c.cells, c.iter.IndexCell())
} else if relation == Subdivided {
// edgeRoot is subdivided into one or more index cells (case 2). We
// find the cells intersected by AB using recursive subdivision.
case Subdivided:
// edgeRoot is subdivided into one or more index cells
// (case 2). We find the cells intersected by AB using
// recursive subdivision.
if !edgeRoot.isFace() {
pcell = PaddedCellFromCellID(edgeRoot, 0)
}
c.computeCellsIntersected(pcell, edgeBound)
case Disjoint:
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions s2/edge_clipping.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ func FaceSegments(a, b Point) []FaceSegment {
// Complete the current segment by finding the point where AB
// exits the current face.
z := faceXYZtoUVW(face, ab)
n := pointUVW{z.Vector}
n := pointUVW(z)

exitAxis := n.exitAxis()
segment.b = n.exitPoint(exitAxis)
Expand Down Expand Up @@ -605,7 +605,7 @@ func moveOriginToValidFace(face int, a, ab Point, aUV r2.Point) (int, r2.Point)

// Otherwise check whether the normal AB even intersects this face.
z := faceXYZtoUVW(face, ab)
n := pointUVW{z.Vector}
n := pointUVW(z)
if n.intersectsFace() {
// Check whether the point where the line AB exits this face is on the
// wrong side of A (by more than the acceptable error tolerance).
Expand Down
2 changes: 2 additions & 0 deletions s2/edge_crosser.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ func (e *EdgeCrosser) EdgeOrVertexChainCrossing(d Point) bool {
return false
case Cross:
return true
case MaybeCross:
// fall through
}
return VertexCrossing(e.a, e.b, c, d)
}
Expand Down
5 changes: 3 additions & 2 deletions s2/edge_crossings.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ func EdgeOrVertexCrossing(a, b, c, d Point) bool {
return false
case Cross:
return true
default:
return VertexCrossing(a, b, c, d)
case MaybeCross:
// Fall through to the final return.
}
return VertexCrossing(a, b, c, d)
}

// Intersection returns the intersection point of two edges AB and CD that cross
Expand Down
4 changes: 2 additions & 2 deletions s2/edge_distances.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func UpdateMinInteriorDistance(x, a, b Point, minDist s1.ChordAngle) (s1.ChordAn
func Project(x, a, b Point) Point {
aXb := a.PointCross(b)
// Find the closest point to X along the great circle through AB.
p := x.Sub(aXb.Mul(x.Dot(aXb.Vector) / aXb.Vector.Norm2()))
p := x.Sub(aXb.Mul(x.Dot(aXb.Vector) / aXb.Norm2()))

// If this point is on the edge AB, then it's the closest point.
if Sign(aXb, a, Point{p}) && Sign(Point{p}, b, aXb) {
Expand Down Expand Up @@ -146,7 +146,7 @@ func InterpolateAtDistance(ax s1.Angle, a, b Point) Point {
// result is always perpendicular to A, even if A=B or A=-B, but it is not
// necessarily unit length. (We effectively normalize it below.)
normal := a.PointCross(b)
tangent := normal.Vector.Cross(a.Vector)
tangent := normal.Cross(a.Vector)

// Now compute the appropriate linear combination of A and "tangent". With
// infinite precision the result would always be unit length, but we
Expand Down
9 changes: 5 additions & 4 deletions s2/edge_distances_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,8 @@ func TestEdgeDistancesInterpolate(t *testing.T) {
test.a, test.b, r, got, test.want)
}
}
if r.Radians() >= 0 && r.Radians() < 0.99*math.Pi {
if r.Radians() >= 0 && r.Radians() < 0.99*math.Pi { // nolint staticcheck
// TODO(rsned): Remove nolint when this test case is added.
// We don't have the parallel ChordAngle variants of
// PointOnLine/Ray/Left/Right
// so the second tests are not added here.
Expand Down Expand Up @@ -478,7 +479,7 @@ func TestEdgeDistancesRepeatedInterpolation(t *testing.T) {
for j := 0; j < 1000; j++ {
a = Interpolate(0.01, a, b)
}
if !a.Vector.IsUnit() {
if !a.IsUnit() {
t.Errorf("repeated Interpolate(%v, %v, %v) calls did not stay unit length for", 0.01, a, b)
}
}
Expand Down Expand Up @@ -725,7 +726,7 @@ func TestEdgeDistancesEdgePairMinDistance(t *testing.T) {
actualA, actualB := EdgePairClosestPoints(test.a0, test.a1, test.b0, test.b1)
if test.wantA == zero {
// either end point works.
if !(actualA == test.a0 || actualA == test.a1) {
if actualA != test.a0 && actualA != test.a1 {
t.Errorf("EdgePairClosestPoints(%v, %v, %v, %v) = %v, want %v or %v", test.a0, test.a1, test.b0, test.b1, actualA, test.a0, test.a1)
}
} else {
Expand All @@ -736,7 +737,7 @@ func TestEdgeDistancesEdgePairMinDistance(t *testing.T) {

if test.wantB == zero {
// either end point works.
if !(actualB == test.b0 || actualB == test.b1) {
if actualB != test.b0 && actualB != test.b1 {
t.Errorf("EdgePairClosestPoints(%v, %v, %v, %v) = %v, want %v or %v", test.a0, test.a1, test.b0, test.b1, actualB, test.b0, test.b1)
}
} else {
Expand Down
28 changes: 12 additions & 16 deletions s2/edge_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,18 +242,14 @@ func testEdgeQueryWithGenerator(t *testing.T,
var indexCaps []Cap
var indexes []*ShapeIndex
for i := 0; i < numIndexes; i++ {
// TODO(rsned): Replace with:
// r := rand.New(rand.NewSource(i))
rand.Seed(int64(i))
indexCaps = append(indexCaps, CapFromCenterAngle(randomPoint(), testCapRadius))
r := rand.New(rand.NewSource(i))
indexCaps = append(indexCaps, CapFromCenterAngle(randomPoint(r), testCapRadius))
indexes = append(indexes, NewShapeIndex())
gen(indexCaps[i], numEdges, indexes[i])
}

for i := 0; i < numQueries; i++ {
// TODO(rsned): Replace with:
// r := rand.New(rand.NewSource(i))
rand.Seed(int64(i))
r := rand.New(rand.NewSource(i))
iIndex := randomUniformInt(numIndexes)
indexCap := indexCaps[iIndex]

Expand All @@ -273,23 +269,23 @@ func testEdgeQueryWithGenerator(t *testing.T,
// Occasionally we don't set any limit on the number of result edges.
// (This may return all edges if we also don't set a distance limit.)
if oneIn(5) {
opts.MaxResults(1 + randomUniformInt(10))
opts.MaxResults(1 + randomUniformInt(10, r))
}

// We set a distance limit 1/3 of the time.
if oneIn(3) {
opts.DistanceLimit(s1.ChordAngleFromAngle(s1.Angle(randomFloat64()) * queryRadius))
opts.DistanceLimit(s1.ChordAngleFromAngle(s1.Angle(randomFloat64(r)) * queryRadius))
}
if oneIn(2) {
// Choose a maximum error whose logarithm is uniformly distributed over
// a reasonable range, except that it is sometimes zero.
opts.MaxError(s1.ChordAngleFromAngle(s1.Angle(math.Pow(1e-4, randomFloat64()) * queryRadius.Radians())))
opts.MaxError(s1.ChordAngleFromAngle(s1.Angle(math.Pow(1e-4, randomFloat64(r)) * queryRadius.Radians())))
}
opts.IncludeInteriors(oneIn(2))

query := newQueryFunc(indexes[iIndex], opts)

switch randomUniformInt(4) {
switch randomUniformInt(4, r) {
case 0:
// Find the edges furthest from a given point.
point := samplePointFromCap(queryCap)
Expand All @@ -299,22 +295,22 @@ func testEdgeQueryWithGenerator(t *testing.T,
// Find the edges furthest from a given edge.
a := samplePointFromCap(queryCap)
b := samplePointFromCap(
CapFromCenterAngle(a, s1.Angle(math.Pow(1e-4, randomFloat64()))*queryRadius))
CapFromCenterAngle(a, s1.Angle(math.Pow(1e-4, randomFloat64(r)))*queryRadius))
target := NewMaxDistanceToEdgeTarget(Edge{a, b})
testFindEdges(target, query)

case 2:
// Find the edges furthest from a given cell.
minLevel := MaxDiagMetric.MinLevel(queryRadius.Radians())
level := minLevel + randomUniformInt(MaxLevel-minLevel+1)
level := minLevel + randomUniformInt(MaxLevel-minLevel+1, r)
a := samplePointFromCap(queryCap)
cell := CellFromCellID(cellIDFromPoint(a).Parent(level))
target := NewMaxDistanceToCellTarget(cell)
testFindEdges(target, query)

case 3:
// Use another one of the pre-built indexes as the target.
jIndex := randomUniformInt(numIndexes)
jIndex := randomUniformInt(numIndexes, r)
target := NewMaxDistanceToShapeIndexTarget(indexes[jIndex])
target.setIncludeInteriors(oneIn(2))
testFindEdges(target, query)
Expand Down Expand Up @@ -438,9 +434,9 @@ func generateEdgeQueryWithTargets(opts *edgeQueryBenchmarkOptions, query *EdgeQu

// Set a specific seed to allow repeatability
// Replace with r := rand.New(rand.NewSource(opts.randomSeed)) and pass through.
rand.Seed(opts.randomSeed)
r := rand.New(rand.NewSource(opts.randomSeed))
opts.randomSeed++
indexCap := CapFromCenterAngle(randomPoint(), opts.radiusKm)
indexCap := CapFromCenterAngle(randomPoint(r), opts.radiusKm)

query.Reset()
queryIndex.Reset()
Expand Down
4 changes: 2 additions & 2 deletions s2/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ import (
)

type encodableRegion interface {
Encode(io.Writer) error
Encode(w io.Writer) error
}

type decodableRegion interface {
Decode(io.Reader) error
Decode(r io.Reader) error
}

const (
Expand Down
7 changes: 4 additions & 3 deletions s2/lax_polygon.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,15 @@ func LaxPolygonFromPolygon(p *Polygon) *LaxPolygon {
func LaxPolygonFromPoints(loops [][]Point) *LaxPolygon {
p := &LaxPolygon{}
p.numLoops = len(loops)
if p.numLoops == 0 {
switch p.numLoops {
case 0:
p.numVerts = 0
p.vertices = nil
} else if p.numLoops == 1 {
case 1:
p.numVerts = len(loops[0])
p.vertices = make([]Point, p.numVerts)
copy(p.vertices, loops[0])
} else {
default:
p.cumulativeVertices = make([]int, p.numLoops+1)
numVertices := 0
for i, loop := range loops {
Expand Down
2 changes: 1 addition & 1 deletion s2/loop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,7 @@ func TestLoopRelations(t *testing.T) {
a1 := cloneLoop(test.a)
a1.Invert()
testLoopNestedPair(t, a1, test.b)
} else if !(test.contains || test.contained || test.covers) {
} else if !test.contains && !test.contained && !test.covers {
// Given loops A and B such that both A and its complement
// intersect both B and its complement, test various
// identities involving these four loops.
Expand Down
2 changes: 1 addition & 1 deletion s2/max_distance_targets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ func TestDistanceTargetMaxShapeIndexTargetCapBound(t *testing.T) {
pTest := randomPoint()
// Check points outside of cap to be away from maxDistance's zero().
if !c.ContainsPoint(pTest) {
var curDist distance = inf
var curDist = inf
var ok bool
if curDist, ok = target.updateDistanceToPoint(pTest, curDist); !ok {
t.Errorf("updateDistanceToPoint failed, but should have succeeded")
Expand Down
6 changes: 3 additions & 3 deletions s2/point.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func OrderedCCW(a, b, c, o Point) bool {

// Distance returns the angle between two points.
func (p Point) Distance(b Point) s1.Angle {
return p.Vector.Angle(b.Vector)
return p.Angle(b.Vector)
}

// ApproxEqual reports whether the two points are similar enough to be equal.
Expand All @@ -133,7 +133,7 @@ func (p Point) ApproxEqual(other Point) bool {

// approxEqual reports whether the two points are within the given epsilon.
func (p Point) approxEqual(other Point, eps s1.Angle) bool {
return p.Vector.Angle(other.Vector) <= eps
return p.Angle(other.Vector) <= eps
}

// ChordAngleBetweenPoints constructs a ChordAngle corresponding to the distance
Expand Down Expand Up @@ -254,7 +254,7 @@ func Ortho(a Point) Point {
temp.Z = 1
case r3.YAxis:
temp.X = 1
default:
case r3.ZAxis:
temp.Y = 1
}
return Point{a.Cross(temp).Normalize()}
Expand Down
2 changes: 1 addition & 1 deletion s2/polygon.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ func (p *Polygon) Validate() error {
for i, l := range p.loops {
// Check for loop errors that don't require building a ShapeIndex.
if err := l.findValidationErrorNoIndex(); err != nil {
return fmt.Errorf("loop %d: %v", i, err)
return fmt.Errorf("loop %d: %w", i, err)
}
// Check that no loop is empty, and that the full loop only appears in the
// full polygon.
Expand Down
Loading