| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package yield |
| |
| import ( |
| "bufio" |
| "io" |
| ) |
| |
| // |
| // |
| // Modify this block of comment lines as needed when changing imports |
| // to avoid perturbing subsequent line numbers (and thus error messages). |
| // |
| // This is L16. |
| |
| func goodIter(yield func(int) bool) { |
| _ = yield(1) && yield(2) && yield(3) // ok |
| } |
| |
| func badIterOR(yield func(int) bool) { |
| _ = yield(1) || // want `yield may be called again \(on L25\) after returning false` |
| yield(2) || // want `yield may be called again \(on L26\) after returning false` |
| yield(3) |
| } |
| |
| func badIterSeq(yield func(int) bool) { |
| yield(1) // want `yield may be called again \(on L31\) after returning false` |
| yield(2) // want `yield may be called again \(on L32\) after returning false` |
| yield(3) // ok |
| } |
| |
| func badIterLoop(yield func(int) bool) { |
| for { |
| yield(1) // want `yield may be called again after returning false` |
| } |
| } |
| |
| func goodIterLoop(yield func(int) bool) { |
| for { |
| if !yield(1) { |
| break |
| } |
| } |
| } |
| |
| func badIterIf(yield func(int) bool) { |
| ok := yield(1) // want `yield may be called again \(on L52\) after returning false` |
| if !ok { |
| yield(2) |
| } else { |
| yield(3) |
| } |
| } |
| |
| func singletonIter(yield func(int) bool) { |
| yield(1) // ok |
| } |
| |
| func twoArgumentYield(yield func(int, int) bool) { |
| _ = yield(1, 1) || // want `yield may be called again \(on L64\) after returning false` |
| yield(2, 2) |
| } |
| |
| func zeroArgumentYield(yield func() bool) { |
| _ = yield() || // want `yield may be called again \(on L69\) after returning false` |
| yield() |
| } |
| |
| func tricky(in io.ReadCloser) func(yield func(string, error) bool) { |
| return func(yield func(string, error) bool) { |
| scan := bufio.NewScanner(in) |
| for scan.Scan() { |
| if !yield(scan.Text(), nil) { // want `yield may be called again \(on L82\) after returning false` |
| _ = in.Close() |
| break |
| } |
| } |
| if err := scan.Err(); err != nil { |
| yield("", err) |
| } |
| } |
| } |
| |
| // Regression test for issue #70598. |
| func shortCircuitAND(yield func(int) bool) { |
| ok := yield(1) |
| ok = ok && yield(2) |
| ok = ok && yield(3) |
| ok = ok && yield(4) |
| } |
| |
| // This example has a bug because a false yield(2) may be followed by yield(3). |
| func tricky2(yield func(int) bool) { |
| cleanup := func() {} |
| ok := yield(1) // want "yield may be called again .on L104" |
| stop := !ok || yield(2) // want "yield may be called again .on L104" |
| if stop { |
| cleanup() |
| } else { |
| // dominated by !stop => !(!ok || yield(2)) => yield(1) && !yield(2): bad. |
| yield(3) |
| } |
| } |
| |
| // This example is sound, but the analyzer reports a false positive. |
| // TODO(adonovan): prune infeasible paths more carefully. |
| func tricky3(yield func(int) bool) { |
| cleanup := func() {} |
| ok := yield(1) // want "yield may be called again .on L118" |
| stop := !ok || !yield(2) // want "yield may be called again .on L118" |
| if stop { |
| cleanup() |
| } else { |
| // dominated by !stop => !(!ok || !yield(2)) => yield(1) && yield(2): good. |
| yield(3) |
| } |
| } |