Skip to content

Commit 82a0ffd

Browse files
committed
Merge remote-tracking branch 'origin/master' into max-min-Option
2 parents d5a91ac + 8439fe9 commit 82a0ffd

File tree

13 files changed

+175
-58
lines changed

13 files changed

+175
-58
lines changed

.travis.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,31 @@ language: scala
66

77
scala:
88
- 2.11.12
9-
- 2.12.11
10-
- 2.13.2
9+
- 2.12.12
10+
- 2.13.3
1111

1212
env:
1313
- SCALAJS_VERSION= ADOPTOPENJDK=8
1414
- SCALAJS_VERSION=0.6.33 ADOPTOPENJDK=8
15-
- SCALAJS_VERSION=1.1.0 ADOPTOPENJDK=8
15+
- SCALAJS_VERSION=1.1.1 ADOPTOPENJDK=8
1616
- SCALAJS_VERSION= ADOPTOPENJDK=11
1717
- SCALAJS_VERSION=0.6.33 ADOPTOPENJDK=11
18-
- SCALAJS_VERSION=1.1.0 ADOPTOPENJDK=11
18+
- SCALAJS_VERSION=1.1.1 ADOPTOPENJDK=11
1919

2020
matrix:
2121

2222
include:
2323

2424
# run migration test
25-
- scala: 2.12.11
25+
- scala: 2.12.12
2626
env: TEST_SCALAFIX=true ADOPTOPENJDK=8
2727

2828
# run binary compatibility test
29-
- scala: 2.12.11
29+
- scala: 2.12.12
3030
env: TEST_BINARY_COMPAT=true ADOPTOPENJDK=8
3131

3232
# run scalafmt
33-
- scala: 2.12.11
33+
- scala: 2.12.12
3434
env: TEST_SCALAFMT=true ADOPTOPENJDK=8
3535

3636
# Scala Native includes

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ The library also adds backported versions of new collection types, currently `sc
3939

4040
## Migration Tool
4141

42-
The migration rules use scalafix. Please see the [official installation instruction](https://scalacenter.github.io/scalafix/docs/users/installation.html) and, in particular, check that your full Scala version is supported (ex 2.12.11).
42+
The migration rules use scalafix. Please see the [official installation instruction](https://scalacenter.github.io/scalafix/docs/users/installation.html) and, in particular, check that your full Scala version is supported (ex 2.12.12).
4343

4444
```scala
4545
// project/plugins.sbt

build.sbt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ lazy val root = project
4848
lazy val junit = libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test
4949

5050
lazy val scala211 = "2.11.12"
51-
lazy val scala212 = "2.12.11"
52-
lazy val scala213 = "2.13.2"
51+
lazy val scala212 = "2.12.12"
52+
lazy val scala213 = "2.13.3"
5353

5454
lazy val compat = MultiScalaCrossProject(JSPlatform, JVMPlatform, NativePlatform)(
5555
"compat",

compat/src/main/scala-2.11/scala/collection/compat/package.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ package scala.collection
1515
import scala.collection.generic.{CanBuildFrom, GenericOrderedCompanion, IsTraversableLike}
1616

1717
import scala.runtime.Tuple2Zipped
18-
import scala.collection.{immutable => i}
18+
import scala.collection.{immutable => i, mutable => m}
1919
import scala.{collection => c}
2020

2121
package object compat extends compat.PackageShared {
@@ -58,4 +58,8 @@ package object compat extends compat.PackageShared {
5858
self: i.Queue[A]): ImmutableQueueExtensionMethods[A] =
5959
new ImmutableQueueExtensionMethods[A](self)
6060

61+
implicit def toMutableQueueExtensionMethods[A](
62+
self: m.Queue[A]): MutableQueueExtensionMethods[A] =
63+
new MutableQueueExtensionMethods[A](self)
64+
6165
}

compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,8 @@ class ImmutableQueueExtensionMethods[A](private val self: i.Queue[A]) extends An
458458
def enqueueAll[B >: A](iter: c.Iterable[B]): i.Queue[B] =
459459
self.enqueue(iter.to[i.Iterable])
460460
}
461+
462+
class MutableQueueExtensionMethods[Element](private val self: m.Queue[Element]) extends AnyVal {
463+
def enqueueAll(iter: c.Iterable[Element]): Unit =
464+
self.enqueue(iter.toIndexedSeq: _*)
465+
}

compat/src/main/scala-2.11_2.12/scala/collection/compat/immutable/LazyList.scala

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,18 @@ final class LazyList[+A] private (private[this] var lazyState: () => LazyList.St
231231

232232
@volatile private[this] var stateEvaluated: Boolean = false
233233
@inline private def stateDefined: Boolean = stateEvaluated
234+
private[this] var midEvaluation = false
234235

235236
private lazy val state: State[A] = {
236-
val res = lazyState()
237+
// if it's already mid-evaluation, we're stuck in an infinite
238+
// self-referential loop (also it's empty)
239+
if (midEvaluation) {
240+
throw new RuntimeException(
241+
"self-referential LazyList or a derivation thereof has no more elements")
242+
}
243+
midEvaluation = true
244+
val res = try lazyState()
245+
finally midEvaluation = false
237246
// if we set it to `true` before evaluating, we may infinite loop
238247
// if something expects `state` to already be evaluated
239248
stateEvaluated = true
@@ -358,7 +367,7 @@ final class LazyList[+A] private (private[this] var lazyState: () => LazyList.St
358367
newLL {
359368
if (isEmpty) suffix match {
360369
case lazyList: LazyList[B] => lazyList.state // don't recompute the LazyList
361-
case _ => stateFromIterator(suffix.toIterator)
370+
case coll => stateFromIterator(coll.toIterator)
362371
} else sCons(head, tail lazyAppendedAll suffix)
363372
}
364373

@@ -1257,7 +1266,7 @@ object LazyList extends SeqFactory[LazyList] {
12571266
* @param hd The first element of the result lazy list
12581267
* @param tl The remaining elements of the result lazy list
12591268
*/
1260-
def apply[A](hd: => A, tl: => LazyList[A]): LazyList[A] = newLL(sCons(hd, tl))
1269+
def apply[A](hd: => A, tl: => LazyList[A]): LazyList[A] = newLL(sCons(hd, newLL(tl.state)))
12611270

12621271
/** Maps a lazy list to its head and tail */
12631272
def unapply[A](xs: LazyList[A]): Option[(A, LazyList[A])] = #::.unapply(xs)
@@ -1270,7 +1279,7 @@ object LazyList extends SeqFactory[LazyList] {
12701279
/** Construct a LazyList consisting of a given first element followed by elements
12711280
* from another LazyList.
12721281
*/
1273-
def #::[B >: A](elem: => B): LazyList[B] = newLL(sCons(elem, l()))
1282+
def #::[B >: A](elem: => B): LazyList[B] = newLL(sCons(elem, newLL(l().state)))
12741283

12751284
/** Construct a LazyList consisting of the concatenation of the given LazyList and
12761285
* another LazyList.

compat/src/main/scala-2.12/scala/collection/compat/package.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ package scala.collection
1414

1515
import scala.collection.generic.{CanBuildFrom, GenericOrderedCompanion, IsTraversableLike}
1616
import scala.{collection => c}
17-
import scala.collection.{mutable => m}
1817
import scala.runtime.Tuple2Zipped
1918
import scala.collection.{immutable => i, mutable => m}
2019

@@ -67,4 +66,8 @@ package object compat extends compat.PackageShared {
6766
implicit def toImmutableQueueExtensionMethods[A](
6867
self: i.Queue[A]): ImmutableQueueExtensionMethods[A] =
6968
new ImmutableQueueExtensionMethods[A](self)
69+
70+
implicit def toMutableQueueExtensionMethods[A](
71+
self: m.Queue[A]): MutableQueueExtensionMethods[A] =
72+
new MutableQueueExtensionMethods[A](self)
7073
}

compat/src/test/scala/test/scala/collection/ImmutableQueueTest.scala

Lines changed: 0 additions & 30 deletions
This file was deleted.

compat/src/test/scala/test/scala/collection/LazyListLazinessTest.scala

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package test.scala.collection
22

33
import org.junit.Test
44
import org.junit.Assert._
5+
import org.junit.Ignore
56

67
import scala.collection.compat.immutable.LazyList
78
import scala.collection.compat._
@@ -217,7 +218,7 @@ class LazyListLazinessTest {
217218
}
218219

219220
@Test
220-
def lazyAppendedAll_appendedAll_properlyLazy(): Unit = {
221+
def lazyAppendedAll_properlyLazy(): Unit = {
221222
genericAppendedColl_properlyLazy(_ lazyAppendedAll _)
222223
}
223224

@@ -715,6 +716,21 @@ class LazyListLazinessTest {
715716
// assertLazyAllSkipping(op, 4)
716717
// }
717718

719+
private def genericCons_unapply_properlyLazy(
720+
unapply: LazyList[Int] => Option[(Int, LazyList[Int])]): Unit = {
721+
assertLazyAllSkipping(unapply, 1)
722+
}
723+
724+
@Test
725+
def cons_unapply_properlyLazy(): Unit = {
726+
genericCons_unapply_properlyLazy(LazyList.cons.unapply)
727+
}
728+
729+
@Test
730+
def `#::_unapply_properlyLazy`(): Unit = {
731+
genericCons_unapply_properlyLazy(LazyList.#::.unapply)
732+
}
733+
718734
/* factory laziness tests */
719735

720736
@Test
@@ -776,24 +792,48 @@ class LazyListLazinessTest {
776792
assertRepeatedlyLazy(factory)
777793
}
778794

779-
@Test
780-
def `#:: properlyLazy`(): Unit = {
781-
val factory = lazyListFactory { init =>
795+
private def genericCons_properlyLazy(cons: (=> Int, => LazyList[Int]) => LazyList[Int]): Unit = {
796+
val headInitFactory = lazyListFactory { init =>
782797
def gen(index: Int): LazyList[Int] = {
783798
def elem(): Int = { init.evaluate(index); index }
784799
if (index >= LazinessChecker.count) LazyList.empty
785-
// else elem() #:: gen(index + 1)
786-
else gen(index + 1).#::(elem())
800+
else cons(elem(), gen(index + 1))
787801
}
788802

789803
gen(0)
790804
}
791-
assertRepeatedlyLazy(factory)
805+
assertRepeatedlyLazy(headInitFactory)
806+
807+
val tailInitFactory = lazyListFactory { init =>
808+
def gen(index: Int): LazyList[Int] = {
809+
if (index >= LazinessChecker.count) LazyList.empty
810+
else {
811+
init.evaluate(index)
812+
cons(index, gen(index + 1))
813+
}
814+
}
815+
816+
LazyList.empty lazyAppendedAll gen(0) // prevent initial state evaluation
817+
}
818+
assertRepeatedlyLazy(tailInitFactory)
819+
}
820+
821+
@Test
822+
@Ignore // TODO: enable after upgrading to 2.13.4+
823+
def cons_properlyLazy(): Unit = {
824+
genericCons_properlyLazy(LazyList.cons(_, _))
825+
}
826+
827+
@Test
828+
@Ignore // TODO: enable after upgrading Scala.js to 1.1.2+
829+
def `#::_properlyLazy`(): Unit = {
830+
// genericCons_properlyLazy(_ #:: _)
831+
genericCons_properlyLazy((hd, tl) => tl.#::(hd))
792832
}
793833

794834
@Test
795835
def `#::: properlyLazy`(): Unit = {
796-
val factory = lazyListFactory { init =>
836+
val headInitFactory = lazyListFactory { init =>
797837
def gen(index: Int): LazyList[Int] = {
798838
def elem(): LazyList[Int] = LazyList.fill(1) { init.evaluate(index); index }
799839
if (index >= LazinessChecker.count) LazyList.empty
@@ -802,7 +842,20 @@ class LazyListLazinessTest {
802842

803843
gen(0)
804844
}
805-
assertRepeatedlyLazy(factory)
845+
assertRepeatedlyLazy(headInitFactory)
846+
847+
val tailInitFactory = lazyListFactory { init =>
848+
def gen(index: Int): LazyList[Int] = {
849+
if (index >= LazinessChecker.count) LazyList.empty
850+
else {
851+
init.evaluate(index)
852+
LazyList.fill(1)(index) #::: gen(index + 1)
853+
}
854+
}
855+
856+
LazyList.empty lazyAppendedAll gen(0) // prevent initial state evaluation
857+
}
858+
assertRepeatedlyLazy(tailInitFactory)
806859
}
807860

808861
@Test

compat/src/test/scala/test/scala/collection/LazyListTest.scala

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package test.scala.collection
22

33
import org.junit.Test
44
import org.junit.Assert._
5+
import org.junit.Ignore
56

67
import scala.collection.compat.immutable.LazyList
78
import scala.collection.compat._
@@ -148,6 +149,7 @@ class LazyListTest {
148149
assertEquals("LazyList(1)", l.toString)
149150
}
150151

152+
@Ignore // TODO enable once Scala.js is upgraded to 1.1.2+
151153
@Test
152154
def testLazyListToStringWhenLazyListHasCyclicReference: Unit = {
153155
lazy val cyc: LazyList[Int] = 1 #:: 2 #:: 3 #:: 4 #:: cyc
@@ -161,7 +163,7 @@ class LazyListTest {
161163
cyc.tail.tail.head
162164
assertEquals("LazyList(1, 2, 3, <not computed>)", cyc.toString)
163165
cyc.tail.tail.tail.head
164-
assertEquals("LazyList(1, 2, 3, 4, <cycle>)", cyc.toString)
166+
assertEquals("LazyList(1, 2, 3, 4, <not computed>)", cyc.toString)
165167
cyc.tail.tail.tail.tail.head
166168
assertEquals("LazyList(1, 2, 3, 4, <cycle>)", cyc.toString)
167169
}
@@ -355,4 +357,37 @@ class LazyListTest {
355357
assertEquals(1 to 10, build(_ ++= LazyList.from(1).take(10)))
356358
assertEquals(1 to 10, build(_ ++= Iterator.from(1).take(10)))
357359
}
360+
361+
@Test
362+
def selfReferentialFailure(): Unit = {
363+
def assertNoStackOverflow[A](lazyList: LazyList[A]): Unit = {
364+
// don't hang the test if we've made a programming error in this test
365+
val finite = lazyList.take(1000)
366+
// AssertUtil.assertThrows[RuntimeException](finite.force, _ contains "self-referential")
367+
try {
368+
finite.force
369+
fail("Expected RuntimeException to be thrown")
370+
} catch { case e: RuntimeException => assertTrue(e.getMessage.contains("self-referential")) }
371+
}
372+
assertNoStackOverflow {
373+
class L { val ll: LazyList[Nothing] = LazyList.empty #::: ll }; (new L).ll
374+
}
375+
assertNoStackOverflow {
376+
class L { val ll: LazyList[Int] = 1 #:: ll.map(_ + 1).filter(_ % 2 == 0) }; (new L).ll
377+
}
378+
class L {
379+
lazy val a: LazyList[Nothing] = LazyList.empty #::: b
380+
lazy val b: LazyList[Nothing] = LazyList.empty #::: a
381+
}
382+
assertNoStackOverflow((new L).a)
383+
assertNoStackOverflow((new L).b)
384+
}
385+
386+
// scala/bug#11931
387+
@Test
388+
def lazyAppendedAllExecutesOnce(): Unit = {
389+
var count = 0
390+
LazyList(1).lazyAppendedAll({ count += 1; Seq(2) }).toList
391+
assertEquals(1, count)
392+
}
358393
}

0 commit comments

Comments
 (0)