Skip to content

Commit f7d6cf8

Browse files
committed
Revert LazyList back to Stream for Shrink
1 parent 543b405 commit f7d6cf8

File tree

4 files changed

+71
-74
lines changed

4 files changed

+71
-74
lines changed

src/main/scala/org/scalacheck/Prop.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import language.reflectiveCalls
1515
import rng.Seed
1616
import util.{Pretty, ConsoleReporter}
1717
import scala.annotation.tailrec
18-
import ScalaVersionSpecific._
1918

2019
/** Helper class to satisfy ScalaJS compilation. Do not use this directly,
2120
* use `Prop.apply` instead. */
@@ -750,7 +749,7 @@ object Prop {
750749
/** Universal quantifier for an explicit generator. Shrinks failed arguments
751750
* with the given shrink function */
752751
def forAllShrink[T, P](g: Gen[T],
753-
shrink: T => LazyList[T])(f: T => P
752+
shrink: T => Stream[T])(f: T => P
754753
)(implicit pv: P => Prop, pp: T => Pretty
755754
): Prop = Prop { prms0 =>
756755

@@ -766,8 +765,8 @@ object Prop {
766765
/*
767766
* Returns the first failed result in Left or success in Right.
768767
*/
769-
def getFirstFailure(xs: LazyList[T]): Either[(T,Result),(T,Result)] = {
770-
assert(!xs.isEmpty, "LazyList cannot be empty")
768+
def getFirstFailure(xs: Stream[T]): Either[(T,Result),(T,Result)] = {
769+
assert(!xs.isEmpty, "Stream cannot be empty")
771770
val results = xs.map(x => (x, result(x)))
772771
results.dropWhile(!_._2.failure).headOption match {
773772
case None => Right(results.head)

src/main/scala/org/scalacheck/Shrink.scala

Lines changed: 63 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,60 +14,59 @@ import language.higherKinds
1414
import util.Buildable
1515
import util.SerializableCanBuildFroms._
1616
import scala.concurrent.duration.{Duration, FiniteDuration}
17-
import ScalaVersionSpecific._
1817

1918
sealed abstract class Shrink[T] extends Serializable {
20-
def shrink(x: T): LazyList[T]
19+
def shrink(x: T): Stream[T]
2120
}
2221

2322
trait ShrinkLowPriority {
2423
/** Default shrink instance */
25-
implicit def shrinkAny[T]: Shrink[T] = Shrink(_ => LazyList.empty)
24+
implicit def shrinkAny[T]: Shrink[T] = Shrink(_ => Stream.empty)
2625
}
2726

2827
object Shrink extends ShrinkLowPriority {
2928

30-
import LazyList.{cons, empty}
29+
import Stream.{cons, empty}
3130
import scala.collection._
3231

33-
/** Interleaves two streams / lazy lists */
34-
private def interleave[T](xs: LazyList[T], ys: LazyList[T]): LazyList[T] =
32+
/** Interleaves two streams */
33+
private def interleave[T](xs: Stream[T], ys: Stream[T]): Stream[T] =
3534
if(xs.isEmpty) ys
3635
else if(ys.isEmpty) xs
3736
else cons(xs.head, cons(ys.head, interleave(xs.tail, ys.tail)))
3837

3938
/** Shrink instance factory */
40-
def apply[T](s: T => LazyList[T]): Shrink[T] = new Shrink[T] {
39+
def apply[T](s: T => Stream[T]): Shrink[T] = new Shrink[T] {
4140
override def shrink(x: T) = s(x)
4241
}
4342

4443
/** Shrink a value */
45-
def shrink[T](x: T)(implicit s: Shrink[T]): LazyList[T] = s.shrink(x)
44+
def shrink[T](x: T)(implicit s: Shrink[T]): Stream[T] = s.shrink(x)
4645

4746
/** Shrink a value, but also return the original value as the first element in
48-
* the resulting stream / lazy list */
49-
def shrinkWithOrig[T](x: T)(implicit s: Shrink[T]): LazyList[T] =
47+
* the resulting stream */
48+
def shrinkWithOrig[T](x: T)(implicit s: Shrink[T]): Stream[T] =
5049
cons(x, s.shrink(x))
5150

5251
/** Shrink instance of container */
5352
implicit def shrinkContainer[C[_],T](implicit v: C[T] => Traversable[T], s: Shrink[T],
5453
b: Buildable[T,C[T]]
5554
): Shrink[C[T]] = Shrink { xs: C[T] =>
5655
val ys = v(xs)
57-
val zs = toLazyList(ys)
58-
removeChunks(ys.size,zs).lazyAppendedAll(shrinkOne(zs)).map(b.fromIterable)
56+
val zs = ys.toStream
57+
removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable)
5958
}
6059

6160
/** Shrink instance of container2 */
6261
implicit def shrinkContainer2[C[_,_],T,U](implicit v: C[T,U] => Traversable[(T,U)], s: Shrink[(T,U)],
6362
b: Buildable[(T,U),C[T,U]]
6463
): Shrink[C[T,U]] = Shrink { xs: C[T,U] =>
6564
val ys = v(xs)
66-
val zs = toLazyList(ys)
67-
removeChunks(ys.size,zs).lazyAppendedAll(shrinkOne(zs)).map(b.fromIterable)
65+
val zs = ys.toStream
66+
removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable)
6867
}
6968

70-
private def removeChunks[T](n: Int, xs: LazyList[T]): LazyList[LazyList[T]] =
69+
private def removeChunks[T](n: Int, xs: Stream[T]): Stream[Stream[T]] =
7170
if (xs.isEmpty) empty
7271
else if (xs.tail.isEmpty) cons(empty, empty)
7372
else {
@@ -76,19 +75,19 @@ object Shrink extends ShrinkLowPriority {
7675
lazy val xs1 = xs.take(n1)
7776
lazy val xs2 = xs.drop(n1)
7877
lazy val xs3 =
79-
for (ys1 <- removeChunks(n1, xs1) if !ys1.isEmpty) yield ys1 lazyAppendedAll xs2
78+
for (ys1 <- removeChunks(n1, xs1) if !ys1.isEmpty) yield ys1 append xs2
8079
lazy val xs4 =
81-
for (ys2 <- removeChunks(n2, xs2) if !ys2.isEmpty) yield xs1 lazyAppendedAll ys2
80+
for (ys2 <- removeChunks(n2, xs2) if !ys2.isEmpty) yield xs1 append ys2
8281

8382
cons(xs1, cons(xs2, interleave(xs3, xs4)))
8483
}
8584

86-
private def shrinkOne[T : Shrink](zs: LazyList[T]): LazyList[LazyList[T]] =
85+
private def shrinkOne[T : Shrink](zs: Stream[T]): Stream[Stream[T]] =
8786
if (zs.isEmpty) empty
8887
else {
8988
val x = zs.head
9089
val xs = zs.tail
91-
shrink(x).map(cons(_,xs)).lazyAppendedAll(shrinkOne(xs).map(cons(x,_)))
90+
shrink(x).map(cons(_,xs)).append(shrinkOne(xs).map(cons(x,_)))
9291
}
9392

9493
/** Shrink instances for numeric data types */
@@ -115,7 +114,7 @@ object Shrink extends ShrinkLowPriority {
115114
T1:Shrink, T2:Shrink
116115
]: Shrink[(T1,T2)] =
117116
Shrink { case (t1,t2) =>
118-
shrink(t1).map((_,t2)) lazyAppendedAll
117+
shrink(t1).map((_,t2)) append
119118
shrink(t2).map((t1,_))
120119
}
121120

@@ -124,8 +123,8 @@ object Shrink extends ShrinkLowPriority {
124123
T1:Shrink, T2:Shrink, T3:Shrink
125124
]: Shrink[(T1,T2,T3)] =
126125
Shrink { case (t1,t2,t3) =>
127-
shrink(t1).map((_, t2, t3)) lazyAppendedAll
128-
shrink(t2).map((t1, _, t3)) lazyAppendedAll
126+
shrink(t1).map((_, t2, t3)) append
127+
shrink(t2).map((t1, _, t3)) append
129128
shrink(t3).map((t1, t2, _))
130129
}
131130

@@ -134,9 +133,9 @@ object Shrink extends ShrinkLowPriority {
134133
T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink
135134
]: Shrink[(T1,T2,T3,T4)] =
136135
Shrink { case (t1,t2,t3,t4) =>
137-
shrink(t1).map((_, t2, t3, t4)) lazyAppendedAll
138-
shrink(t2).map((t1, _, t3, t4)) lazyAppendedAll
139-
shrink(t3).map((t1, t2, _, t4)) lazyAppendedAll
136+
shrink(t1).map((_, t2, t3, t4)) append
137+
shrink(t2).map((t1, _, t3, t4)) append
138+
shrink(t3).map((t1, t2, _, t4)) append
140139
shrink(t4).map((t1, t2, t3, _))
141140
}
142141

@@ -145,10 +144,10 @@ object Shrink extends ShrinkLowPriority {
145144
T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink
146145
]: Shrink[(T1,T2,T3,T4,T5)] =
147146
Shrink { case (t1,t2,t3,t4,t5) =>
148-
shrink(t1).map((_, t2, t3, t4, t5)) lazyAppendedAll
149-
shrink(t2).map((t1, _, t3, t4, t5)) lazyAppendedAll
150-
shrink(t3).map((t1, t2, _, t4, t5)) lazyAppendedAll
151-
shrink(t4).map((t1, t2, t3, _, t5)) lazyAppendedAll
147+
shrink(t1).map((_, t2, t3, t4, t5)) append
148+
shrink(t2).map((t1, _, t3, t4, t5)) append
149+
shrink(t3).map((t1, t2, _, t4, t5)) append
150+
shrink(t4).map((t1, t2, t3, _, t5)) append
152151
shrink(t5).map((t1, t2, t3, t4, _))
153152
}
154153

@@ -157,11 +156,11 @@ object Shrink extends ShrinkLowPriority {
157156
T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink
158157
]: Shrink[(T1,T2,T3,T4,T5,T6)] =
159158
Shrink { case (t1,t2,t3,t4,t5,t6) =>
160-
shrink(t1).map((_, t2, t3, t4, t5, t6)) lazyAppendedAll
161-
shrink(t2).map((t1, _, t3, t4, t5, t6)) lazyAppendedAll
162-
shrink(t3).map((t1, t2, _, t4, t5, t6)) lazyAppendedAll
163-
shrink(t4).map((t1, t2, t3, _, t5, t6)) lazyAppendedAll
164-
shrink(t5).map((t1, t2, t3, t4, _, t6)) lazyAppendedAll
159+
shrink(t1).map((_, t2, t3, t4, t5, t6)) append
160+
shrink(t2).map((t1, _, t3, t4, t5, t6)) append
161+
shrink(t3).map((t1, t2, _, t4, t5, t6)) append
162+
shrink(t4).map((t1, t2, t3, _, t5, t6)) append
163+
shrink(t5).map((t1, t2, t3, t4, _, t6)) append
165164
shrink(t6).map((t1, t2, t3, t4, t5, _))
166165
}
167166

@@ -170,12 +169,12 @@ object Shrink extends ShrinkLowPriority {
170169
T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink, T7:Shrink
171170
]: Shrink[(T1,T2,T3,T4,T5,T6,T7)] =
172171
Shrink { case (t1,t2,t3,t4,t5,t6,t7) =>
173-
shrink(t1).map((_, t2, t3, t4, t5, t6, t7)) lazyAppendedAll
174-
shrink(t2).map((t1, _, t3, t4, t5, t6, t7)) lazyAppendedAll
175-
shrink(t3).map((t1, t2, _, t4, t5, t6, t7)) lazyAppendedAll
176-
shrink(t4).map((t1, t2, t3, _, t5, t6, t7)) lazyAppendedAll
177-
shrink(t5).map((t1, t2, t3, t4, _, t6, t7)) lazyAppendedAll
178-
shrink(t6).map((t1, t2, t3, t4, t5, _, t7)) lazyAppendedAll
172+
shrink(t1).map((_, t2, t3, t4, t5, t6, t7)) append
173+
shrink(t2).map((t1, _, t3, t4, t5, t6, t7)) append
174+
shrink(t3).map((t1, t2, _, t4, t5, t6, t7)) append
175+
shrink(t4).map((t1, t2, t3, _, t5, t6, t7)) append
176+
shrink(t5).map((t1, t2, t3, t4, _, t6, t7)) append
177+
shrink(t6).map((t1, t2, t3, t4, t5, _, t7)) append
179178
shrink(t7).map((t1, t2, t3, t4, t5, t6, _))
180179
}
181180

@@ -185,13 +184,13 @@ object Shrink extends ShrinkLowPriority {
185184
T7:Shrink, T8:Shrink
186185
]: Shrink[(T1,T2,T3,T4,T5,T6,T7,T8)] =
187186
Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8) =>
188-
shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8)) lazyAppendedAll
189-
shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8)) lazyAppendedAll
190-
shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8)) lazyAppendedAll
191-
shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8)) lazyAppendedAll
192-
shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8)) lazyAppendedAll
193-
shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8)) lazyAppendedAll
194-
shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8)) lazyAppendedAll
187+
shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8)) append
188+
shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8)) append
189+
shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8)) append
190+
shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8)) append
191+
shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8)) append
192+
shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8)) append
193+
shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8)) append
195194
shrink(t8).map((t1, t2, t3, t4, t5, t6, t7, _))
196195
}
197196

@@ -201,14 +200,14 @@ object Shrink extends ShrinkLowPriority {
201200
T7:Shrink, T8:Shrink, T9:Shrink
202201
]: Shrink[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] =
203202
Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8,t9) =>
204-
shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8, t9)) lazyAppendedAll
205-
shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8, t9)) lazyAppendedAll
206-
shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8, t9)) lazyAppendedAll
207-
shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8, t9)) lazyAppendedAll
208-
shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8, t9)) lazyAppendedAll
209-
shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8, t9)) lazyAppendedAll
210-
shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8, t9)) lazyAppendedAll
211-
shrink(t8).map((t1, t2, t3, t4, t5, t6, t7, _, t9)) lazyAppendedAll
203+
shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8, t9)) append
204+
shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8, t9)) append
205+
shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8, t9)) append
206+
shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8, t9)) append
207+
shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8, t9)) append
208+
shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8, t9)) append
209+
shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8, t9)) append
210+
shrink(t8).map((t1, t2, t3, t4, t5, t6, t7, _, t9)) append
212211
shrink(t9).map((t1, t2, t3, t4, t5, t6, t7, t8, _))
213212
}
214213

@@ -222,7 +221,7 @@ object Shrink extends ShrinkLowPriority {
222221

223222
implicit val shrinkDuration: Shrink[Duration] = Shrink {
224223
case d: FiniteDuration => shrinkFiniteDuration.shrink(d)
225-
case _ => LazyList.empty
224+
case _ => Stream.empty
226225
}
227226

228227
/** Transform a Shrink[T] to a Shrink[U] where T and U are two isomorphic types
@@ -245,15 +244,15 @@ final class ShrinkIntegral[T](implicit ev: Integral[T]) extends Shrink[T] {
245244
val skipNegation = gteq(negate(one), one)
246245

247246
// assumes x is non-zero.
248-
private def halves(x: T): LazyList[T] = {
247+
private def halves(x: T): Stream[T] = {
249248
val q = quot(x, two)
250-
if (equiv(q, zero)) LazyList(zero)
249+
if (equiv(q, zero)) Stream(zero)
251250
else if (skipNegation) q #:: halves(q)
252251
else q #:: negate(q) #:: halves(q)
253252
}
254253

255-
def shrink(x: T): LazyList[T] =
256-
if (equiv(x, zero)) LazyList.empty[T] else halves(x)
254+
def shrink(x: T): Stream[T] =
255+
if (equiv(x, zero)) Stream.empty[T] else halves(x)
257256
}
258257

259258
final class ShrinkFractional[T](implicit ev: Fractional[T]) extends Shrink[T] {
@@ -268,9 +267,9 @@ final class ShrinkFractional[T](implicit ev: Fractional[T]) extends Shrink[T] {
268267
def closeToZero(x: T): Boolean = lteq(abs(x), small)
269268

270269
// assumes x is not close to zero
271-
private def halves(x: T): LazyList[T] = {
270+
private def halves(x: T): Stream[T] = {
272271
val q = div(x, two)
273-
if (closeToZero(q)) LazyList(zero)
272+
if (closeToZero(q)) Stream(zero)
274273
else q #:: negate(q) #:: halves(q)
275274
}
276275

@@ -283,7 +282,7 @@ final class ShrinkFractional[T](implicit ev: Fractional[T]) extends Shrink[T] {
283282
!lt(div(x, two), x)
284283
}
285284

286-
def shrink(x: T): LazyList[T] =
287-
if (closeToZero(x) || isUnusual(x)) LazyList.empty[T]
285+
def shrink(x: T): Stream[T] =
286+
if (closeToZero(x) || isUnusual(x)) Stream.empty[T]
288287
else halves(x)
289288
}

src/main/scala/org/scalacheck/commands/Commands.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ package org.scalacheck.commands
1111

1212
import org.scalacheck._
1313
import scala.util.{Try, Success, Failure}
14-
import ScalaVersionSpecific._
1514

1615
/** An API for stateful testing in ScalaCheck.
1716
*
@@ -271,8 +270,8 @@ trait Commands {
271270
)
272271

273272
private implicit val shrinkActions = Shrink[Actions] { as =>
274-
val shrinkedCmds: LazyList[Actions] =
275-
Shrink.shrink(as.seqCmds).map(cs => as.copy(seqCmds = cs)) lazyAppendedAll
273+
val shrinkedCmds: Stream[Actions] =
274+
Shrink.shrink(as.seqCmds).map(cs => as.copy(seqCmds = cs)) append
276275
Shrink.shrink(as.parCmds).map(cs => as.copy(parCmds = cs))
277276

278277
Shrink.shrinkWithOrig[State](as.s)(shrinkState) flatMap { state =>

src/test/scala/org/scalacheck/ShrinkSpecification.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ import scala.concurrent.duration.{Duration, FiniteDuration}
1717

1818
object ShrinkSpecification extends Properties("Shrink") {
1919

20-
def shrinkClosure[T : Shrink](x: T): LazyList[T] = {
20+
def shrinkClosure[T : Shrink](x: T): Stream[T] = {
2121
val xs = shrink[T](x)
2222
if(xs.isEmpty) xs
23-
else xs.lazyAppendedAll(xs.take(1).map(shrinkClosure[T]).flatten)
23+
else xs.append(xs.take(1).map(shrinkClosure[T]).flatten)
2424
}
2525

2626
property("byte") = forAll { n: Byte =>
@@ -105,7 +105,7 @@ object ShrinkSpecification extends Properties("Shrink") {
105105

106106
/* Ensure that shrink[T] terminates. (#244)
107107
*
108-
* Let's say shrinking "terminates" when the stream / lazy list of values
108+
* Let's say shrinking "terminates" when the stream of values
109109
* becomes empty. We can empirically determine the longest possible
110110
* sequence for a given type before termination. (Usually this
111111
* involves using the type's MinValue.)

0 commit comments

Comments
 (0)