summaryrefslogtreecommitdiff
path: root/test/junit
diff options
context:
space:
mode:
Diffstat (limited to 'test/junit')
-rw-r--r--test/junit/scala/collection/IndexedSeqOptimizedTest.scala13
-rw-r--r--test/junit/scala/collection/IterableViewLikeTest.scala20
-rw-r--r--test/junit/scala/collection/IteratorTest.scala133
-rw-r--r--test/junit/scala/collection/PagedSeq.scala16
-rw-r--r--test/junit/scala/collection/SeqViewTest.scala16
-rw-r--r--test/junit/scala/collection/StreamTest.scala18
-rw-r--r--test/junit/scala/collection/TraversableOnceTest.scala8
-rw-r--r--test/junit/scala/collection/convert/NullSafetyTest.scala279
-rw-r--r--test/junit/scala/collection/immutable/ListTest.scala49
-rw-r--r--test/junit/scala/collection/immutable/PagedSeqTest.scala28
-rw-r--r--test/junit/scala/collection/immutable/QueueTest.scala (renamed from test/junit/scala/collection/QueueTest.scala)0
-rw-r--r--test/junit/scala/collection/immutable/RangeConsistencyTest.scala (renamed from test/junit/scala/collection/NumericRangeTest.scala)0
-rw-r--r--test/junit/scala/collection/immutable/StreamTest.scala108
-rw-r--r--test/junit/scala/collection/immutable/TreeMapTest.scala20
-rw-r--r--test/junit/scala/collection/immutable/TreeSetTest.scala20
-rw-r--r--test/junit/scala/collection/mutable/ArrayBufferTest.scala36
-rw-r--r--test/junit/scala/collection/mutable/ArraySortingTest.scala (renamed from test/junit/scala/collection/ArraySortingTest.scala)0
-rw-r--r--test/junit/scala/collection/mutable/BitSetTest.scala22
-rw-r--r--test/junit/scala/collection/mutable/PriorityQueueTest.scala (renamed from test/junit/scala/collection/PriorityQueueTest.scala)0
-rw-r--r--test/junit/scala/collection/mutable/VectorTest.scala (renamed from test/junit/scala/collection/VectorTest.scala)0
-rw-r--r--test/junit/scala/io/SourceTest.scala86
-rw-r--r--test/junit/scala/issues/BytecodeTests.scala80
-rw-r--r--test/junit/scala/math/BigDecimalTest.scala6
-rw-r--r--test/junit/scala/math/NumericTest.scala2
-rw-r--r--test/junit/scala/math/OrderingTest.scala61
-rw-r--r--test/junit/scala/reflect/internal/PrintersTest.scala15
-rw-r--r--test/junit/scala/reflect/internal/ScopeTest.scala2
-rw-r--r--test/junit/scala/reflect/internal/util/AbstractFileClassLoaderTest.scala138
-rw-r--r--test/junit/scala/tools/nsc/SampleTest.scala3
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala24
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala50
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala95
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala80
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala8
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala99
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala83
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala221
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala60
-rw-r--r--test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala208
-rw-r--r--test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala159
-rw-r--r--test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala18
-rw-r--r--test/junit/scala/tools/nsc/settings/SettingsTest.scala16
-rw-r--r--test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala12
-rw-r--r--test/junit/scala/tools/nsc/symtab/StdNamesTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala31
-rw-r--r--test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala555
-rw-r--r--test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala143
-rw-r--r--test/junit/scala/tools/testing/AssertUtil.scala20
-rw-r--r--test/junit/scala/util/SpecVersionTest.scala (renamed from test/junit/scala/util/t7265.scala)4
-rw-r--r--test/junit/scala/util/matching/CharRegexTest.scala (renamed from test/junit/scala/util/matching/regextract-char.scala)0
51 files changed, 2944 insertions, 125 deletions
diff --git a/test/junit/scala/collection/IndexedSeqOptimizedTest.scala b/test/junit/scala/collection/IndexedSeqOptimizedTest.scala
index e5382907af..419e1454cb 100644
--- a/test/junit/scala/collection/IndexedSeqOptimizedTest.scala
+++ b/test/junit/scala/collection/IndexedSeqOptimizedTest.scala
@@ -13,4 +13,17 @@ class IndexedSeqOptimizedTest {
assertEquals(0, (Array(2): collection.mutable.WrappedArray[Int]).lastIndexWhere(_ => true, 1))
assertEquals(2, "abc123".lastIndexWhere(_.isLetter, 6))
}
+
+ @Test
+ def hasCorrectDropAndTakeMethods() {
+ assertEquals("", "abc" take Int.MinValue)
+ assertEquals("", "abc" takeRight Int.MinValue)
+ assertEquals("abc", "abc" drop Int.MinValue)
+ assertEquals("abc", "abc" dropRight Int.MinValue)
+
+ assertArrayEquals(Array.empty[Int], Array(1, 2, 3) take Int.MinValue)
+ assertArrayEquals(Array.empty[Int], Array(1, 2, 3) takeRight Int.MinValue)
+ assertArrayEquals(Array(1, 2, 3), Array(1, 2, 3) drop Int.MinValue)
+ assertArrayEquals(Array(1, 2, 3), Array(1, 2, 3) dropRight Int.MinValue)
+ }
}
diff --git a/test/junit/scala/collection/IterableViewLikeTest.scala b/test/junit/scala/collection/IterableViewLikeTest.scala
new file mode 100644
index 0000000000..55da02744b
--- /dev/null
+++ b/test/junit/scala/collection/IterableViewLikeTest.scala
@@ -0,0 +1,20 @@
+package scala.collection
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class IterableViewLikeTest {
+
+ @Test
+ def hasCorrectDropAndTakeMethods() {
+ val iter = Iterable(1, 2, 3)
+
+ assertEquals(Iterable.empty[Int], iter.view take Int.MinValue force)
+ assertEquals(Iterable.empty[Int], iter.view takeRight Int.MinValue force)
+ assertEquals(iter, iter.view drop Int.MinValue force)
+ assertEquals(iter, iter.view dropRight Int.MinValue force)
+ }
+}
diff --git a/test/junit/scala/collection/IteratorTest.scala b/test/junit/scala/collection/IteratorTest.scala
index b7a9805c9f..d5389afd0c 100644
--- a/test/junit/scala/collection/IteratorTest.scala
+++ b/test/junit/scala/collection/IteratorTest.scala
@@ -6,11 +6,14 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import scala.tools.testing.AssertUtil._
+
+import Seq.empty
+
@RunWith(classOf[JUnit4])
class IteratorTest {
- @Test
- def groupedIteratorShouldNotAskForUnneededElement(): Unit = {
+ @Test def groupedIteratorShouldNotAskForUnneededElement(): Unit = {
var counter = 0
val it = new Iterator[Int] { var i = 0 ; def hasNext = { counter = i; true } ; def next = { i += 1; i } }
val slidingIt = it sliding 2
@@ -25,4 +28,130 @@ class IteratorTest {
slidingIt.next
assertEquals("Counter should be one, that means we didn't look further than needed", 1, counter)
}
+
+ @Test def dropDoesNotGrowStack(): Unit = {
+ def it = new Iterator[Throwable] { def hasNext = true ; def next = new Throwable }
+
+ assertEquals(it.drop(1).next.getStackTrace.length, it.drop(1).drop(1).next.getStackTrace.length)
+ }
+
+ @Test def dropIsChainable(): Unit = {
+ assertSameElements(1 to 4, Iterator from 0 take 5 drop 1)
+ assertSameElements(3 to 4, Iterator from 0 take 5 drop 3)
+ assertSameElements(empty, Iterator from 0 take 5 drop 5)
+ assertSameElements(empty, Iterator from 0 take 5 drop 10)
+ assertSameElements(0 to 4, Iterator from 0 take 5 drop 0)
+ assertSameElements(0 to 4, Iterator from 0 take 5 drop -1)
+ assertSameElements(2 to 8 by 2, Iterator from 0 take 5 drop 1 map (2 * _))
+ assertSameElements(2 to 8 by 2, Iterator from 0 take 5 map (2 * _) drop 1)
+ assertSameElements(3 to 4, Iterator from 0 take 5 drop 1 drop 2)
+ assertSameElements(3 to 4, Iterator from 0 take 5 drop 2 drop 1)
+ }
+
+ @Test def sliceIsChainable(): Unit = {
+ assertSameElements(3 to 6, Iterator from 0 slice (3, 7))
+ assertSameElements(empty, Iterator from 0 slice (3, 3))
+ assertSameElements(0 to 2, Iterator from 0 slice (-1, 3))
+ assertSameElements(empty, Iterator from 0 slice (3, -1))
+ assertSameElements(6 to 12 by 2, Iterator from 0 slice (3, 7) map (2 * _))
+ assertSameElements(6 to 12 by 2, Iterator from 0 map (2 * _) slice (3, 7))
+ assertSameElements(4 to 6, Iterator from 0 slice (3, 7) drop 1)
+ assertSameElements(4 to 7, Iterator from 0 drop 1 slice (3, 7))
+ assertSameElements(4 to 5, Iterator from 0 slice (3, 7) slice (1, 3))
+ assertSameElements(4 to 6, Iterator from 0 slice (3, 7) slice (1, 10))
+ }
+
+ // test/files/run/iterator-concat.scala
+ @Test def concatIsStackFriendly(): Unit = {
+ // Create `size` Function0s, each of which evaluates to an Iterator
+ // which produces 1. Then fold them over ++ to get a single iterator,
+ // which should sum to "size".
+ def mk(size: Int): Iterator[Int] = {
+ //val closures = (1 to size).toList.map(x => (() => Iterator(1)))
+ //closures.foldLeft(Iterator.empty: Iterator[Int])((res, f) => res ++ f())
+ List.fill(size)(() => Iterator(1)).foldLeft(Iterator.empty: Iterator[Int])((res, f) => res ++ f())
+ }
+ assertEquals(100, mk(100).sum)
+ assertEquals(1000, mk(1000).sum)
+ assertEquals(10000, mk(10000).sum)
+ assertEquals(100000, mk(100000).sum)
+ }
+
+ @Test def from(): Unit = {
+ val it1 = Iterator.from(-1)
+ val it2 = Iterator.from(0, -1)
+ assertEquals(-1, it1.next())
+ assertEquals(0, it2.next())
+ }
+ @Test def range(): Unit = {
+ assertEquals(5, Iterator.range(0, 10, 2).size)
+ assertEquals(0, Iterator.range(0, 10, -2).size)
+ assertEquals(5, Iterator.range(10, 0, -2).size)
+ assertEquals(0, Iterator.range(10, 0, 2).size)
+ assertEquals(1, Iterator.range(0, 10, 11).size)
+ assertEquals(10, Iterator.range(0, 10, 1).size)
+ assertEquals(10, Iterator.range(10, 0, -1).size)
+ }
+ @Test def range3(): Unit = {
+ val r1 = Iterator.range(0, 10)
+ assertTrue(r1 contains 5)
+ assertTrue(r1 contains 6)
+ assertFalse(r1 contains 4)
+ val r2a = Iterator.range(0, 10, 2)
+ assertFalse(r2a contains 5)
+ val r2b = Iterator.range(0, 10, 2)
+ assertTrue(r2b contains 6)
+ val r3 = Iterator.range(0, 10, 11)
+ assertFalse(r3 contains 5)
+ assertTrue(r3.isEmpty)
+ }
+ @Test def take(): Unit = {
+ assertEquals(10, (Iterator from 0 take 10).size)
+ }
+ @Test def foreach(): Unit = {
+ val it1 = Iterator.from(0) take 20
+ var n = 0
+ it1 foreach { n += _ }
+ assertEquals(190, n)
+ }
+ // ticket #429
+ @Test def fromArray(): Unit = {
+ val a = List(1, 2, 3, 4).toArray
+ var xs0 = a.iterator.toList;
+ var xs1 = a.slice(0, 1).iterator
+ var xs2 = a.slice(0, 2).iterator
+ var xs3 = a.slice(0, 3).iterator
+ var xs4 = a.slice(0, 4).iterator
+ assertEquals(14, xs0.size + xs1.size + xs2.size + xs3.size + xs4.size)
+ }
+ @Test def toSeq(): Unit = {
+ assertEquals("1x2x3x4x5", List(1, 2, 3, 4, 5).iterator.mkString("x"))
+ }
+ @Test def indexOf(): Unit = {
+ assertEquals(3, List(1, 2, 3, 4, 5).iterator.indexOf(4))
+ assertEquals(-1, List(1, 2, 3, 4, 5).iterator.indexOf(16))
+ }
+ @Test def indexWhere(): Unit = {
+ assertEquals(3, List(1, 2, 3, 4, 5).iterator.indexWhere { x: Int => x >= 4 })
+ assertEquals(-1, List(1, 2, 3, 4, 5).iterator.indexWhere { x: Int => x >= 16 })
+ }
+ // iterator-iterate-lazy.scala
+ // was java.lang.UnsupportedOperationException: tail of empty list
+ @Test def iterateIsSufficientlyLazy(): Unit = {
+ //Iterator.iterate((1 to 5).toList)(_.tail).takeWhile(_.nonEmpty).toList // suffices
+ Iterator.iterate((1 to 5).toList)(_.tail).takeWhile(_.nonEmpty).map(_.head).toList
+ }
+ // SI-3516
+ @Test def toStreamIsSufficientlyLazy(): Unit = {
+ val results = collection.mutable.ListBuffer.empty[Int]
+ def mkIterator = (1 to 5).iterator map (x => { results += x ; x })
+ def mkInfinite = Iterator continually { results += 1 ; 1 }
+
+ // Stream is strict in its head so we should see 1 from each of them.
+ val s1 = mkIterator.toStream
+ val s2 = mkInfinite.toStream
+ // back and forth without slipping into nontermination.
+ results += (Stream from 1).toIterator.drop(10).toStream.drop(10).toIterator.next()
+ assertSameElements(List(1,1,21), results)
+ }
}
diff --git a/test/junit/scala/collection/PagedSeq.scala b/test/junit/scala/collection/PagedSeq.scala
deleted file mode 100644
index 5f83cf6f31..0000000000
--- a/test/junit/scala/collection/PagedSeq.scala
+++ /dev/null
@@ -1,16 +0,0 @@
-package scala.collection.immutable
-
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.junit.Test
-import org.junit.Assert._
-
-/* Test for SI-6615 */
-@RunWith(classOf[JUnit4])
-class PagedSeqTest {
- @Test
- def rovingDoesNotNPE(): Unit = {
- // should not NPE, and should equal the given Seq
- assertEquals(Seq('a'), PagedSeq.fromStrings(List.fill(5000)("a")).slice(4096, 4097))
- }
-}
diff --git a/test/junit/scala/collection/SeqViewTest.scala b/test/junit/scala/collection/SeqViewTest.scala
new file mode 100644
index 0000000000..24474fc4b9
--- /dev/null
+++ b/test/junit/scala/collection/SeqViewTest.scala
@@ -0,0 +1,16 @@
+package scala.collection
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Assert._
+import org.junit.Test
+
+@RunWith(classOf[JUnit4])
+class SeqViewTest {
+
+ @Test
+ def test_SI8691() {
+ // Really just testing to make sure ++: doesn't throw an exception
+ assert( Seq(1,2) ++: Seq(3,4).view == Seq(1,2,3,4) )
+ }
+}
diff --git a/test/junit/scala/collection/StreamTest.scala b/test/junit/scala/collection/StreamTest.scala
deleted file mode 100644
index 6dc1c79a48..0000000000
--- a/test/junit/scala/collection/StreamTest.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package scala.collection.immutable
-
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.junit.Test
-import org.junit.Assert._
-
-@RunWith(classOf[JUnit4])
-class StreamTest {
-
- @Test
- def t6727_and_t6440(): Unit = {
- assertTrue(Stream.continually(()).filter(_ => true).take(2) == Seq((), ()))
- assertTrue(Stream.continually(()).filterNot(_ => false).take(2) == Seq((), ()))
- assertTrue(Stream(1,2,3,4,5).filter(_ < 4) == Seq(1,2,3))
- assertTrue(Stream(1,2,3,4,5).filterNot(_ > 4) == Seq(1,2,3,4))
- }
-}
diff --git a/test/junit/scala/collection/TraversableOnceTest.scala b/test/junit/scala/collection/TraversableOnceTest.scala
index 56d8312336..196174c199 100644
--- a/test/junit/scala/collection/TraversableOnceTest.scala
+++ b/test/junit/scala/collection/TraversableOnceTest.scala
@@ -43,8 +43,8 @@ class TraversableOnceTest {
def testReturnTheFirstMatch() = {
val d = List(1, 2, 3, 4, 5, 6, 7, 8)
def f(x: Int) = x % 3;
- assert(d.maxBy(f) == 2, "If multiple elements evaluted to the largest value, maxBy should return the first one.")
- assert(d.minBy(f) == 3, "If multiple elements evaluted to the largest value, minBy should return the first one.")
+ assert(d.maxBy(f) == 2, "If multiple elements evaluated to the largest value, maxBy should return the first one.")
+ assert(d.minBy(f) == 3, "If multiple elements evaluated to the largest value, minBy should return the first one.")
}
// Make sure it evaluates f no more than list.length times.
@@ -56,7 +56,7 @@ class TraversableOnceTest {
evaluatedCountOfMaxBy += 1
x * 10
})
- assert(evaluatedCountOfMaxBy == list.length, s"maxBy: should evaluate f only ${list.length} times, but it evaluted $evaluatedCountOfMaxBy times.")
+ assert(evaluatedCountOfMaxBy == list.length, s"maxBy: should evaluate f only ${list.length} times, but it evaluated $evaluatedCountOfMaxBy times.")
var evaluatedCountOfMinBy = 0
@@ -64,7 +64,7 @@ class TraversableOnceTest {
evaluatedCountOfMinBy += 1
x * 10
})
- assert(evaluatedCountOfMinBy == list.length, s"minBy: should evaluate f only ${list.length} times, but it evaluted $evaluatedCountOfMinBy times.")
+ assert(evaluatedCountOfMinBy == list.length, s"minBy: should evaluate f only ${list.length} times, but it evaluated $evaluatedCountOfMinBy times.")
}
}
diff --git a/test/junit/scala/collection/convert/NullSafetyTest.scala b/test/junit/scala/collection/convert/NullSafetyTest.scala
new file mode 100644
index 0000000000..de5481d9e2
--- /dev/null
+++ b/test/junit/scala/collection/convert/NullSafetyTest.scala
@@ -0,0 +1,279 @@
+package scala.collection.convert
+
+import java.{util => ju, lang => jl}
+import ju.{concurrent => juc}
+
+import org.junit.Test
+import org.junit.experimental.runners.Enclosed
+import org.junit.runner.RunWith
+
+import scala.collection.JavaConversions._
+import scala.collection.JavaConverters._
+import scala.collection.{mutable, concurrent}
+
+@RunWith(classOf[Enclosed])
+object NullSafetyTest {
+
+ /*
+ * Pertinent: SI-9113
+ * Tests to insure that wrappers return null instead of wrapping it as a collection
+ */
+
+ class ToScala {
+
+ @Test def testIteratorWrapping(): Unit = {
+ val nullJIterator: ju.Iterator[AnyRef] = null
+ val iterator: Iterator[AnyRef] = nullJIterator
+
+ assert(iterator == null)
+ }
+
+ @Test def testEnumerationWrapping(): Unit = {
+ val nullJEnumeration: ju.Enumeration[AnyRef] = null
+ val enumeration: Iterator[AnyRef] = nullJEnumeration
+
+ assert(enumeration == null)
+ }
+
+ @Test def testIterableWrapping(): Unit = {
+ val nullJIterable: jl.Iterable[AnyRef] = null
+ val iterable: Iterable[AnyRef] = nullJIterable
+
+ assert(iterable == null)
+ }
+
+ @Test def testCollectionWrapping(): Unit = {
+ val nullJCollection: ju.Collection[AnyRef] = null
+ val collection: Iterable[AnyRef] = nullJCollection
+
+ assert(collection == null)
+ }
+
+ @Test def testBufferWrapping(): Unit = {
+ val nullJList: ju.List[AnyRef] = null
+ val buffer: mutable.Buffer[AnyRef] = nullJList
+
+ assert(buffer == null)
+ }
+
+ @Test def testSetWrapping(): Unit = {
+ val nullJSet: ju.Set[AnyRef] = null
+ val set: mutable.Set[AnyRef] = nullJSet
+
+ assert(set == null)
+ }
+
+ @Test def testMapWrapping(): Unit = {
+ val nullJMap: ju.Map[AnyRef, AnyRef] = null
+ val map: mutable.Map[AnyRef, AnyRef] = nullJMap
+
+ assert(map == null)
+ }
+
+ @Test def testConcurrentMapWrapping(): Unit = {
+ val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null
+ val conMap: concurrent.Map[AnyRef, AnyRef] = nullJConMap
+
+ assert(conMap == null)
+ }
+
+ @Test def testDictionaryWrapping(): Unit = {
+ val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null
+ val dict: mutable.Map[AnyRef, AnyRef] = nullJDict
+
+ assert(dict == null)
+ }
+
+
+ @Test def testPropertyWrapping(): Unit = {
+ val nullJProps: ju.Properties = null
+ val props: mutable.Map[String, String] = nullJProps
+
+ assert(props == null)
+ }
+
+ @Test def testIteratorDecoration(): Unit = {
+ val nullJIterator: ju.Iterator[AnyRef] = null
+
+ assert(nullJIterator.asScala == null)
+ }
+
+ @Test def testEnumerationDecoration(): Unit = {
+ val nullJEnumeration: ju.Enumeration[AnyRef] = null
+
+ assert(nullJEnumeration.asScala == null)
+ }
+
+ @Test def testIterableDecoration(): Unit = {
+ val nullJIterable: jl.Iterable[AnyRef] = null
+
+ assert(nullJIterable.asScala == null)
+ }
+
+ @Test def testCollectionDecoration(): Unit = {
+ val nullJCollection: ju.Collection[AnyRef] = null
+
+ assert(nullJCollection.asScala == null)
+ }
+
+ @Test def testBufferDecoration(): Unit = {
+ val nullJBuffer: ju.List[AnyRef] = null
+
+ assert(nullJBuffer.asScala == null)
+ }
+
+ @Test def testSetDecoration(): Unit = {
+ val nullJSet: ju.Set[AnyRef] = null
+
+ assert(nullJSet.asScala == null)
+ }
+
+ @Test def testMapDecoration(): Unit = {
+ val nullJMap: ju.Map[AnyRef, AnyRef] = null
+
+ assert(nullJMap.asScala == null)
+ }
+
+ @Test def testConcurrentMapDecoration(): Unit = {
+ val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null
+
+ assert(nullJConMap.asScala == null)
+ }
+
+ @Test def testDictionaryDecoration(): Unit = {
+ val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null
+
+ assert(nullJDict.asScala == null)
+ }
+
+ @Test def testPropertiesDecoration(): Unit = {
+ val nullJProperties: ju.Properties = null
+
+ assert(nullJProperties.asScala == null)
+ }
+ }
+
+ class ToJava {
+
+ @Test def testIteratorWrapping(): Unit = {
+ val nullIterator: Iterator[AnyRef] = null
+ val jIterator: ju.Iterator[AnyRef] = nullIterator
+
+ assert(jIterator == null)
+ }
+
+ @Test def testEnumerationWrapping(): Unit = {
+ val nullEnumeration: Iterator[AnyRef] = null
+ val enumeration: ju.Iterator[AnyRef] = nullEnumeration
+
+ assert(enumeration == null)
+ }
+
+ @Test def testIterableWrapping(): Unit = {
+ val nullIterable: Iterable[AnyRef] = null
+ val iterable: jl.Iterable[AnyRef] = asJavaIterable(nullIterable)
+
+ assert(iterable == null)
+ }
+
+ @Test def testCollectionWrapping(): Unit = {
+ val nullCollection: Iterable[AnyRef] = null
+ val collection: ju.Collection[AnyRef] = nullCollection
+
+ assert(collection == null)
+ }
+
+ @Test def testBufferWrapping(): Unit = {
+ val nullList: mutable.Buffer[AnyRef] = null
+ val buffer: ju.List[AnyRef] = nullList
+
+ assert(buffer == null)
+ }
+
+ @Test def testSetWrapping(): Unit = {
+ val nullSet: mutable.Set[AnyRef] = null
+ val set: ju.Set[AnyRef] = nullSet
+
+ assert(set == null)
+ }
+
+ @Test def testMapWrapping(): Unit = {
+ val nullMap: mutable.Map[AnyRef, AnyRef] = null
+ val map: ju.Map[AnyRef, AnyRef] = nullMap
+
+ assert(map == null)
+ }
+
+ @Test def testConcurrentMapWrapping(): Unit = {
+ val nullConMap: concurrent.Map[AnyRef, AnyRef] = null
+ val conMap: juc.ConcurrentMap[AnyRef, AnyRef] = nullConMap
+
+ assert(conMap == null)
+ }
+
+ @Test def testDictionaryWrapping(): Unit = {
+ val nullDict: mutable.Map[AnyRef, AnyRef] = null
+ val dict: ju.Dictionary[AnyRef, AnyRef] = nullDict
+
+ assert(dict == null)
+ }
+
+ // Implicit conversion to ju.Properties is not available
+
+ @Test def testIteratorDecoration(): Unit = {
+ val nullIterator: Iterator[AnyRef] = null
+
+ assert(nullIterator.asJava == null)
+ }
+
+ @Test def testEnumerationDecoration(): Unit = {
+ val nullEnumeration: Iterator[AnyRef] = null
+
+ assert(nullEnumeration.asJavaEnumeration == null)
+ }
+
+ @Test def testIterableDecoration(): Unit = {
+ val nullIterable: Iterable[AnyRef] = null
+
+ assert(nullIterable.asJava == null)
+ }
+
+ @Test def testCollectionDecoration(): Unit = {
+ val nullCollection: Iterable[AnyRef] = null
+
+ assert(nullCollection.asJavaCollection == null)
+ }
+
+ @Test def testBufferDecoration(): Unit = {
+ val nullBuffer: mutable.Buffer[AnyRef] = null
+
+ assert(nullBuffer.asJava == null)
+ }
+
+ @Test def testSetDecoration(): Unit = {
+ val nullSet: Set[AnyRef] = null
+
+ assert(nullSet.asJava == null)
+ }
+
+ @Test def testMapDecoration(): Unit = {
+ val nullMap: mutable.Map[AnyRef, AnyRef] = null
+
+ assert(nullMap.asJava == null)
+ }
+
+ @Test def testConcurrentMapDecoration(): Unit = {
+ val nullConMap: concurrent.Map[AnyRef, AnyRef] = null
+
+ assert(nullConMap.asJava == null)
+ }
+
+ @Test def testDictionaryDecoration(): Unit = {
+ val nullDict: mutable.Map[AnyRef, AnyRef] = null
+
+ assert(nullDict.asJavaDictionary == null)
+ }
+
+ // Decorator conversion to ju.Properties is not available
+ }
+}
diff --git a/test/junit/scala/collection/immutable/ListTest.scala b/test/junit/scala/collection/immutable/ListTest.scala
new file mode 100644
index 0000000000..1006801029
--- /dev/null
+++ b/test/junit/scala/collection/immutable/ListTest.scala
@@ -0,0 +1,49 @@
+package scala.collection.immutable
+
+import org.junit.{Assert, Test}
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.ref.WeakReference
+
+@RunWith(classOf[JUnit4])
+class ListTest {
+ /**
+ * Test that empty iterator does not hold reference
+ * to complete List
+ */
+ @Test
+ def testIteratorGC(): Unit = {
+ var num = 0
+ var emptyIterators = Seq.empty[(Iterator[Int], WeakReference[List[Int]])]
+
+ do {
+ val list = List.fill(10000)(num)
+ val ref = WeakReference(list)
+
+ val i = list.iterator
+
+ while (i.hasNext) i.next()
+
+ emptyIterators = (i, ref) +: emptyIterators
+
+ num+=1
+ } while (emptyIterators.forall(_._2.get.isDefined) && num<1000)
+
+ // check something is result to protect from JIT optimizations
+ for ((i, _) <- emptyIterators) {
+ Assert.assertTrue(i.isEmpty)
+ }
+
+ // await gc up to ~5 seconds
+ var forceLoops = 50
+ while (emptyIterators.forall(_._2.get.isDefined) && forceLoops>0) {
+ System.gc()
+ Thread.sleep(100)
+ forceLoops -= 1
+ }
+
+ // real assertion
+ Assert.assertTrue(emptyIterators.exists(_._2.get.isEmpty))
+ }
+}
diff --git a/test/junit/scala/collection/immutable/PagedSeqTest.scala b/test/junit/scala/collection/immutable/PagedSeqTest.scala
new file mode 100644
index 0000000000..2b576a3655
--- /dev/null
+++ b/test/junit/scala/collection/immutable/PagedSeqTest.scala
@@ -0,0 +1,28 @@
+package scala.collection.immutable
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import org.junit.Assert._
+
+@RunWith(classOf[JUnit4])
+class PagedSeqTest {
+ // should not NPE, and should equal the given Seq
+ @Test
+ def test_SI6615(): Unit = {
+ assertEquals(Seq('a'), PagedSeq.fromStrings(List.fill(5000)("a")).slice(4096, 4097))
+ }
+
+ // Slices shouldn't read outside where they belong
+ @Test
+ def test_SI6519 {
+ var readAttempt = 0
+ val sideEffectingIterator = new Iterator[Int] {
+ def hasNext = readAttempt < 65536
+ def next = { readAttempt += 1; readAttempt }
+ }
+ val s = PagedSeq.fromIterator(sideEffectingIterator).slice(0,2).mkString
+ assertEquals(s, "12")
+ assert(readAttempt <= 4096)
+ }
+}
diff --git a/test/junit/scala/collection/QueueTest.scala b/test/junit/scala/collection/immutable/QueueTest.scala
index 9a40d8fc90..9a40d8fc90 100644
--- a/test/junit/scala/collection/QueueTest.scala
+++ b/test/junit/scala/collection/immutable/QueueTest.scala
diff --git a/test/junit/scala/collection/NumericRangeTest.scala b/test/junit/scala/collection/immutable/RangeConsistencyTest.scala
index 3980c31577..3980c31577 100644
--- a/test/junit/scala/collection/NumericRangeTest.scala
+++ b/test/junit/scala/collection/immutable/RangeConsistencyTest.scala
diff --git a/test/junit/scala/collection/immutable/StreamTest.scala b/test/junit/scala/collection/immutable/StreamTest.scala
new file mode 100644
index 0000000000..437cbc8926
--- /dev/null
+++ b/test/junit/scala/collection/immutable/StreamTest.scala
@@ -0,0 +1,108 @@
+package scala.collection.immutable
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import org.junit.Assert._
+
+import scala.ref.WeakReference
+import scala.util.Try
+
+@RunWith(classOf[JUnit4])
+class StreamTest {
+
+ @Test
+ def t6727_and_t6440(): Unit = {
+ assertTrue(Stream.continually(()).filter(_ => true).take(2) == Seq((), ()))
+ assertTrue(Stream.continually(()).filterNot(_ => false).take(2) == Seq((), ()))
+ assertTrue(Stream(1,2,3,4,5).filter(_ < 4) == Seq(1,2,3))
+ assertTrue(Stream(1,2,3,4,5).filterNot(_ > 4) == Seq(1,2,3,4))
+ }
+
+ /** Test helper to verify that the given Stream operation allows
+ * GC of the head during processing of the tail.
+ */
+ def assertStreamOpAllowsGC(op: (=> Stream[Int], Int => Unit) => Any, f: Int => Unit): Unit = {
+ val msgSuccessGC = "GC success"
+ val msgFailureGC = "GC failure"
+
+ // A stream of 500 elements at most. We will test that the head can be collected
+ // while processing the tail. After each element we will GC and wait 10 ms, so a
+ // failure to collect will take roughly 5 seconds.
+ val ref = WeakReference( Stream.from(1).take(500) )
+
+ def gcAndThrowIfCollected(n: Int): Unit = {
+ System.gc() // try to GC
+ Thread.sleep(10) // give it 10 ms
+ if (ref.get.isEmpty) throw new RuntimeException(msgSuccessGC) // we're done if head collected
+ f(n)
+ }
+
+ val res = Try { op(ref(), gcAndThrowIfCollected) }.failed // success is indicated by an
+ val msg = res.map(_.getMessage).getOrElse(msgFailureGC) // exception with expected message
+ // failure is indicated by no
+ assertTrue(msg == msgSuccessGC) // exception, or one with different message
+ }
+
+ @Test
+ def foreach_allows_GC() {
+ assertStreamOpAllowsGC(_.foreach(_), _ => ())
+ }
+
+ @Test
+ def filter_all_foreach_allows_GC() {
+ assertStreamOpAllowsGC(_.filter(_ => true).foreach(_), _ => ())
+ }
+
+ @Test // SI-8990
+ def withFilter_after_first_foreach_allows_GC: Unit = {
+ assertStreamOpAllowsGC(_.withFilter(_ > 1).foreach(_), _ => ())
+ }
+
+ @Test // SI-8990
+ def withFilter_after_first_withFilter_foreach_allows_GC: Unit = {
+ assertStreamOpAllowsGC(_.withFilter(_ > 1).withFilter(_ < 100).foreach(_), _ => ())
+ }
+
+ @Test // SI-8990
+ def withFilter_can_retry_after_exception_thrown_in_filter: Unit = {
+ // use mutable state to control an intermittent failure in filtering the Stream
+ var shouldThrow = true
+
+ val wf = Stream.from(1).take(10).withFilter { n =>
+ if (shouldThrow && n == 5) throw new RuntimeException("n == 5") else n > 5
+ }
+
+ assertTrue( Try { wf.map(identity) }.isFailure ) // throws on n == 5
+
+ shouldThrow = false // won't throw next time
+
+ assertTrue( wf.map(identity).length == 5 ) // success instead of NPE
+ }
+
+ /** Test helper to verify that the given Stream operation is properly lazy in the tail */
+ def assertStreamOpLazyInTail(op: (=> Stream[Int]) => Stream[Int], expectedEvaluated: List[Int]): Unit = {
+ // mutable state to record every strict evaluation
+ var evaluated: List[Int] = Nil
+
+ def trackEffectsOnNaturals: Stream[Int] = {
+ def loop(i: Int): Stream[Int] = { evaluated ++= List(i); i #:: loop(i + 1) }
+ loop(1)
+ }
+
+ // call op on a stream which records every strict evaluation
+ val result = op(trackEffectsOnNaturals)
+
+ assertTrue( evaluated == expectedEvaluated )
+ }
+
+ @Test // SI-9134
+ def filter_map_properly_lazy_in_tail: Unit = {
+ assertStreamOpLazyInTail(_.filter(_ % 2 == 0).map(identity), List(1, 2))
+ }
+
+ @Test // SI-9134
+ def withFilter_map_properly_lazy_in_tail: Unit = {
+ assertStreamOpLazyInTail(_.withFilter(_ % 2 == 0).map(identity), List(1, 2))
+ }
+}
diff --git a/test/junit/scala/collection/immutable/TreeMapTest.scala b/test/junit/scala/collection/immutable/TreeMapTest.scala
new file mode 100644
index 0000000000..4c21b94b24
--- /dev/null
+++ b/test/junit/scala/collection/immutable/TreeMapTest.scala
@@ -0,0 +1,20 @@
+package scala.collection.immutable
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class TreeMapTest {
+
+ @Test
+ def hasCorrectDropAndTakeMethods() {
+ val tree = TreeMap(1 -> "a", 2 -> "b", 3 -> "c")
+
+ assertEquals(TreeMap.empty[Int, String], tree take Int.MinValue)
+ assertEquals(TreeMap.empty[Int, String], tree takeRight Int.MinValue)
+ assertEquals(tree, tree drop Int.MinValue)
+ assertEquals(tree, tree dropRight Int.MinValue)
+ }
+}
diff --git a/test/junit/scala/collection/immutable/TreeSetTest.scala b/test/junit/scala/collection/immutable/TreeSetTest.scala
new file mode 100644
index 0000000000..8efe1bfeb8
--- /dev/null
+++ b/test/junit/scala/collection/immutable/TreeSetTest.scala
@@ -0,0 +1,20 @@
+package scala.collection.immutable
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class TreeSetTest {
+
+ @Test
+ def hasCorrectDropAndTakeMethods() {
+ val set = TreeSet(1, 2, 3)
+
+ assertEquals(TreeSet.empty[Int], set take Int.MinValue)
+ assertEquals(TreeSet.empty[Int], set takeRight Int.MinValue)
+ assertEquals(set, set drop Int.MinValue)
+ assertEquals(set, set dropRight Int.MinValue)
+ }
+}
diff --git a/test/junit/scala/collection/mutable/ArrayBufferTest.scala b/test/junit/scala/collection/mutable/ArrayBufferTest.scala
new file mode 100644
index 0000000000..8c83164027
--- /dev/null
+++ b/test/junit/scala/collection/mutable/ArrayBufferTest.scala
@@ -0,0 +1,36 @@
+package scala.collection.mutable
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.{Assert, Test}
+
+import scala.tools.testing.AssertUtil
+
+/* Test for SI-9043 */
+@RunWith(classOf[JUnit4])
+class ArrayBufferTest {
+ @Test
+ def testInsertAll: Unit = {
+ val traver = ArrayBuffer(2, 4, 5, 7)
+ val testSeq = List(1, 3, 6, 9)
+
+ def insertAt(x: Int) = {
+ val clone = traver.clone()
+ clone.insertAll(x, testSeq)
+ clone
+ }
+
+ // Just insert some at position 0
+ Assert.assertEquals(ArrayBuffer(1, 3, 6, 9, 2, 4, 5, 7), insertAt(0))
+
+ // Insert in the middle
+ Assert.assertEquals(ArrayBuffer(2, 4, 1, 3, 6, 9, 5, 7), insertAt(2))
+
+ // No strange last position weirdness
+ Assert.assertEquals(ArrayBuffer(2, 4, 5, 7, 1, 3, 6, 9), insertAt(traver.size))
+
+ // Overflow is caught
+ AssertUtil.assertThrows[IndexOutOfBoundsException] { insertAt(-1) }
+ AssertUtil.assertThrows[IndexOutOfBoundsException] { insertAt(traver.size + 10) }
+ }
+}
diff --git a/test/junit/scala/collection/ArraySortingTest.scala b/test/junit/scala/collection/mutable/ArraySortingTest.scala
index 4e54b39ce7..4e54b39ce7 100644
--- a/test/junit/scala/collection/ArraySortingTest.scala
+++ b/test/junit/scala/collection/mutable/ArraySortingTest.scala
diff --git a/test/junit/scala/collection/mutable/BitSetTest.scala b/test/junit/scala/collection/mutable/BitSetTest.scala
new file mode 100644
index 0000000000..8d164b50d4
--- /dev/null
+++ b/test/junit/scala/collection/mutable/BitSetTest.scala
@@ -0,0 +1,22 @@
+package scala.collection.mutable
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.{Test, Ignore}
+
+@RunWith(classOf[JUnit4])
+class BitSetTest {
+ // Test for SI-8910
+ @Test def capacityExpansionTest() {
+ val bitSet = BitSet.empty
+ val size = bitSet.toBitMask.length
+ bitSet ^= bitSet
+ assert(bitSet.toBitMask.length == size, "Capacity of bitset changed after ^=")
+ bitSet |= bitSet
+ assert(bitSet.toBitMask.length == size, "Capacity of bitset changed after |=")
+ bitSet &= bitSet
+ assert(bitSet.toBitMask.length == size, "Capacity of bitset changed after &=")
+ bitSet &~= bitSet
+ assert(bitSet.toBitMask.length == size, "Capacity of bitset changed after &~=")
+ }
+}
diff --git a/test/junit/scala/collection/PriorityQueueTest.scala b/test/junit/scala/collection/mutable/PriorityQueueTest.scala
index a14f1bf4c8..a14f1bf4c8 100644
--- a/test/junit/scala/collection/PriorityQueueTest.scala
+++ b/test/junit/scala/collection/mutable/PriorityQueueTest.scala
diff --git a/test/junit/scala/collection/VectorTest.scala b/test/junit/scala/collection/mutable/VectorTest.scala
index e9c4d44a72..e9c4d44a72 100644
--- a/test/junit/scala/collection/VectorTest.scala
+++ b/test/junit/scala/collection/mutable/VectorTest.scala
diff --git a/test/junit/scala/io/SourceTest.scala b/test/junit/scala/io/SourceTest.scala
new file mode 100644
index 0000000000..3138a4589c
--- /dev/null
+++ b/test/junit/scala/io/SourceTest.scala
@@ -0,0 +1,86 @@
+
+package scala.io
+
+import org.junit.Test
+import org.junit.Assert._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil._
+
+import java.io.{ Console => _, _ }
+
+@RunWith(classOf[JUnit4])
+class SourceTest {
+
+ private implicit val `our codec` = Codec.UTF8
+ private val charSet = Codec.UTF8.charSet.name
+
+ private def sampler = """
+ |Big-endian and little-endian approaches aren't
+ |readily interchangeable in general, because the
+ |laws of arithmetic send signals leftward from
+ |the bits that are "least significant."
+ |""".stripMargin.trim
+
+ private def in = new ByteArrayInputStream(sampler.getBytes)
+
+ @Test def canIterateLines() = {
+ assertEquals(sampler.lines.size, (Source fromString sampler).getLines.size)
+ }
+ @Test def canCustomizeReporting() = {
+ class CapitalReporting(is: InputStream) extends BufferedSource(is) {
+ override def report(pos: Int, msg: String, out: PrintStream): Unit = {
+ out print f"$pos%04x: ${msg.toUpperCase}"
+ }
+ class OffsetPositioner extends Positioner(null) {
+ override def next(): Char = {
+ ch = iter.next()
+ pos = pos + 1
+ ch
+ }
+ }
+ withPositioning(new OffsetPositioner)
+ }
+ val s = new CapitalReporting(in)
+ // skip to next line and report an error
+ do {
+ val c = s.next()
+ } while (s.ch != '\n')
+ s.next()
+ val out = new ByteArrayOutputStream
+ val ps = new PrintStream(out, true, charSet)
+ s.reportError(s.pos, "That doesn't sound right.", ps)
+ assertEquals("0030: THAT DOESN'T SOUND RIGHT.", out.toString(charSet))
+ }
+ @Test def canAltCustomizeReporting() = {
+ class CapitalReporting(is: InputStream)(implicit codec: Codec) extends Source {
+ override val iter = {
+ val r = new InputStreamReader(is, codec.decoder)
+ Iterator continually (codec wrap r.read()) takeWhile (_ != -1) map (_.toChar)
+ }
+ override def report(pos: Int, msg: String, out: PrintStream): Unit = {
+ out print f"$pos%04x: ${msg.toUpperCase}"
+ }
+ private[this] var _pos: Int = _
+ override def pos = _pos
+ private[this] var _ch: Char = _
+ override def ch = _ch
+ override def next = {
+ _ch = iter.next()
+ _pos += 1
+ _ch
+ }
+ }
+ val s = new CapitalReporting(in)
+ // skip to next line and report an error
+ do {
+ val c = s.next()
+ } while (s.ch != '\n')
+ s.next()
+ val out = new ByteArrayOutputStream
+ val ps = new PrintStream(out, true, charSet)
+ s.reportError(s.pos, "That doesn't sound right.", ps)
+ assertEquals("0030: THAT DOESN'T SOUND RIGHT.", out.toString(charSet))
+ }
+}
diff --git a/test/junit/scala/issues/BytecodeTests.scala b/test/junit/scala/issues/BytecodeTests.scala
new file mode 100644
index 0000000000..d4ed063a03
--- /dev/null
+++ b/test/junit/scala/issues/BytecodeTests.scala
@@ -0,0 +1,80 @@
+package scala.issues
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes
+import scala.tools.nsc.backend.jvm.AsmUtils
+import scala.tools.nsc.backend.jvm.CodeGenTools._
+import org.junit.Assert._
+import scala.collection.JavaConverters._
+import scala.tools.partest.ASMConverters._
+
+@RunWith(classOf[JUnit4])
+class BytecodeTests {
+ val compiler = newCompiler()
+
+ @Test
+ def t8731(): Unit = {
+ val code =
+ """class C {
+ | def f(x: Int) = (x: @annotation.switch) match {
+ | case 1 => 0
+ | case 2 => 1
+ | case 3 => 2
+ | }
+ | final val K = 10
+ | def g(x: Int) = (x: @annotation.switch) match {
+ | case K => 0
+ | case 1 => 10
+ | case 2 => 20
+ | }
+ |}
+ """.stripMargin
+
+ val List(c) = compileClasses(compiler)(code)
+
+ assertTrue(getSingleMethod(c, "f").instructions.count(_.isInstanceOf[TableSwitch]) == 1)
+ assertTrue(getSingleMethod(c, "g").instructions.count(_.isInstanceOf[LookupSwitch]) == 1)
+ }
+
+ @Test
+ def t8926(): Unit = {
+ import scala.reflect.internal.util.BatchSourceFile
+
+ // this test cannot be implemented using partest because of its mixed-mode compilation strategy:
+ // partest first compiles all files with scalac, then the java files, and then again the scala
+ // using the output classpath. this shadows the bug SI-8926.
+
+ val annotA =
+ """import java.lang.annotation.Retention;
+ |import java.lang.annotation.RetentionPolicy;
+ |@Retention(RetentionPolicy.RUNTIME)
+ |public @interface AnnotA { }
+ """.stripMargin
+ val annotB = "public @interface AnnotB { }"
+
+ val scalaSrc =
+ """@AnnotA class A
+ |@AnnotB class B
+ """.stripMargin
+
+ val compiler = newCompiler()
+ val run = new compiler.Run()
+ run.compileSources(List(new BatchSourceFile("AnnotA.java", annotA), new BatchSourceFile("AnnotB.java", annotB), new BatchSourceFile("Test.scala", scalaSrc)))
+ val outDir = compiler.settings.outputDirs.getSingleOutput.get
+ val outfiles = (for (f <- outDir.iterator if !f.isDirectory) yield (f.name, f.toByteArray)).toList
+
+ def check(classfile: String, annotName: String) = {
+ val f = (outfiles collect { case (`classfile`, bytes) => AsmUtils.readClass(bytes) }).head
+ val descs = f.visibleAnnotations.asScala.map(_.desc).toList
+ assertTrue(descs.toString, descs exists (_ contains annotName))
+ }
+
+ check("A.class", "AnnotA")
+
+ // known issue SI-8928: the visibility of AnnotB should be CLASS, but annotation classes without
+ // a @Retention annotation are currently emitted as RUNTIME.
+ check("B.class", "AnnotB")
+ }
+}
diff --git a/test/junit/scala/math/BigDecimalTest.scala b/test/junit/scala/math/BigDecimalTest.scala
index d1ba96fcc8..c7a63da890 100644
--- a/test/junit/scala/math/BigDecimalTest.scala
+++ b/test/junit/scala/math/BigDecimalTest.scala
@@ -222,4 +222,10 @@ class BigDecimalTest {
for (a <- different; b <- different if (a ne b))
assert(a != b, "BigDecimal representations of Double mistakenly conflated")
}
+
+ // Make sure hash code agrees with decimal representation of Double
+ @Test
+ def test_SI8970() {
+ assert((0.1).## == BigDecimal(0.1).##)
+ }
}
diff --git a/test/junit/scala/math/NumericTest.scala b/test/junit/scala/math/NumericTest.scala
index 4f0657f471..9bf7d4f1e4 100644
--- a/test/junit/scala/math/NumericTest.scala
+++ b/test/junit/scala/math/NumericTest.scala
@@ -1,4 +1,4 @@
-
+package scala.math
import org.junit.Assert._
import org.junit.Test
diff --git a/test/junit/scala/math/OrderingTest.scala b/test/junit/scala/math/OrderingTest.scala
new file mode 100644
index 0000000000..218622b8b4
--- /dev/null
+++ b/test/junit/scala/math/OrderingTest.scala
@@ -0,0 +1,61 @@
+package scala.math
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class OrderingTest {
+
+ /* Test for SI-9077 */
+ @Test
+ def testReverseOrdering {
+ def check[T: Ordering](t1: T, t2: T): Unit = {
+ val O = Ordering[T]
+ val R = O.reverse
+ assertEquals(O.min(t1, t2), R.max(t1, t2))
+ assertEquals(O.max(t1, t2), R.min(t1, t2))
+
+ assertEquals(O.lteq(t1, t2), R.lteq(t2, t1))
+ assertEquals(O.lt(t1, t2), R.lt(t2, t1))
+ assertEquals(O.gteq(t1, t2), R.gteq(t2, t1))
+ assertEquals(O.gt(t1, t2), R.gt(t2, t1))
+ assertEquals(O.compare(t1, t2), R.compare(t2, t1))
+
+ assertEquals(O.equiv(t1, t2), R.equiv(t1, t2))
+
+ assertEquals(O.on((x: T) => x).min(t1, t2), R.on((x: T) => x).max(t1, t2))
+
+ assertEquals(O.tryCompare(t1, t2), R.tryCompare(t2, t1))
+
+ assertEquals(O.mkOrderingOps(t1).<(t2), R.mkOrderingOps(t2).<(t1))
+ assertEquals(O.mkOrderingOps(t1).<=(t2), R.mkOrderingOps(t2).<=(t1))
+ assertEquals(O.mkOrderingOps(t1).>(t2), R.mkOrderingOps(t2).>(t1))
+ assertEquals(O.mkOrderingOps(t1).>=(t2), R.mkOrderingOps(t2).>=(t1))
+
+ assertEquals(O.mkOrderingOps(t1).min(t2), R.mkOrderingOps(t1).max(t2))
+ assertEquals(O.mkOrderingOps(t1).max(t2), R.mkOrderingOps(t1).min(t2))
+ }
+ def checkAll[T: Ordering](ts: T*): Unit = {
+ for (t1 <- ts; t2 <- ts) check(t1, t2)
+ }
+ checkAll[Unit](())
+ checkAll[Boolean](true, false)
+ checkAll[Byte](Byte.MinValue, -1.toByte, 0.toByte, 1.toByte, Byte.MaxValue)
+ checkAll[Char](Char.MinValue, -1.toChar, 0.toChar, 1.toChar, Char.MaxValue)
+ checkAll[Short](Short.MinValue, -1, 0, 1, Short.MaxValue)
+ checkAll[Int](Int.MinValue, -1, 0, 1, Int.MaxValue)
+ checkAll[Double](Double.MinValue, -1, -0, 0, 1, Double.MaxValue)
+ checkAll[Float](Float.MinValue, -1, -0, 0, 1, Float.MaxValue)
+
+ checkAll[BigInt](Int.MinValue, -1, 0, 1, Int.MaxValue)
+ checkAll[BigDecimal](Int.MinValue, -1, -0, 1, Int.MaxValue)
+ checkAll[String]("", "a", "b", "bb")
+ checkAll[String]("", "a", "b", "bb")
+ checkAll[Option[Int]](None, Some(1), Some(2))
+ checkAll[Iterable[Int]](Nil, List(1), List(1, 2))
+ checkAll[(Int, Int)]((1, 2), (1, 3), (4, 5))
+ }
+}
+
diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala
index 1458b942dc..9bfe6eecb8 100644
--- a/test/junit/scala/reflect/internal/PrintersTest.scala
+++ b/test/junit/scala/reflect/internal/PrintersTest.scala
@@ -24,10 +24,10 @@ object PrinterHelper {
resultCode.lines mkString s"$LF"
def assertResultCode(code: String)(parsedCode: String = "", typedCode: String = "", wrap: Boolean = false, printRoot: Boolean = false) = {
- def toolboxTree(tree: => Tree) = try{
+ def toolboxTree(tree: => Tree) = try {
tree
} catch {
- case e:scala.tools.reflect.ToolBoxError => throw new Exception(e.getMessage + ": " + code)
+ case e:scala.tools.reflect.ToolBoxError => throw new Exception(e.getMessage + ": " + code, e)
}
def wrapCode(source: String) = {
@@ -125,6 +125,8 @@ trait BasePrintTests {
@Test def testName19 = assertPrintedCode("""class `class`""")
@Test def testName20 = assertPrintedCode("""class `test name`""")
+
+ @Test def testName21 = assertPrintedCode("""class `test.name`""")
@Test def testIfExpr1 = assertResultCode(code = sm"""
|val a = 1
@@ -354,6 +356,13 @@ trait ClassPrintTests {
| def y = "test"
|}""")
+ @Test def testClassConstructorModifiers = assertPrintedCode("class X private (x: scala.Int)")
+
+ @Test def testClassConstructorModifierVisibility = assertPrintedCode(sm"""
+ |object A {
+ | class X protected[A] (x: scala.Int)
+ |}""")
+
@Test def testClassWithPublicParams = assertPrintedCode("class X(val x: scala.Int, val s: scala.Predef.String)")
@Test def testClassWithParams1 = assertPrintedCode("class X(x: scala.Int, s: scala.Predef.String)")
@@ -1186,4 +1195,4 @@ trait QuasiTreesPrintTests {
| };
| ()
|}""")
-} \ No newline at end of file
+}
diff --git a/test/junit/scala/reflect/internal/ScopeTest.scala b/test/junit/scala/reflect/internal/ScopeTest.scala
index 5166620189..1ab24facac 100644
--- a/test/junit/scala/reflect/internal/ScopeTest.scala
+++ b/test/junit/scala/reflect/internal/ScopeTest.scala
@@ -1,4 +1,4 @@
-package symtab
+package scala.reflect.internal
import scala.tools.nsc.symtab
diff --git a/test/junit/scala/reflect/internal/util/AbstractFileClassLoaderTest.scala b/test/junit/scala/reflect/internal/util/AbstractFileClassLoaderTest.scala
new file mode 100644
index 0000000000..a2537ddab7
--- /dev/null
+++ b/test/junit/scala/reflect/internal/util/AbstractFileClassLoaderTest.scala
@@ -0,0 +1,138 @@
+package scala.reflect.internal.util
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class AbstractFileClassLoaderTest {
+
+ import scala.reflect.io._
+ import scala.io.Source
+ import scala.io.Codec.UTF8
+ import scala.reflect.io.Streamable
+ import java.net.{ URLClassLoader, URL }
+
+ implicit def `we love utf8` = UTF8
+ implicit class `abs file ops`(f: AbstractFile) {
+ def writeContent(s: String): Unit = Streamable.closing(f.bufferedOutput)(os => os write s.getBytes(UTF8.charSet))
+ }
+ implicit class `url slurp`(url: URL) {
+ def slurp(): String = Streamable.slurp(url)
+ }
+
+ val NoClassLoader: ClassLoader = null
+
+ def fuzzBuzzBooz: (AbstractFile, AbstractFile) = {
+ val fuzz = new VirtualDirectory("fuzz", None)
+ val buzz = fuzz subdirectoryNamed "buzz"
+ val booz = buzz fileNamed "booz.class"
+ (fuzz, booz)
+ }
+
+ @Test
+ def afclGetsParent(): Unit = {
+ val p = new URLClassLoader(Array.empty[URL])
+ val d = new VirtualDirectory("vd", None)
+ val x = new AbstractFileClassLoader(d, p)
+ assertSame(p, x.getParent)
+ }
+
+ @Test
+ def afclGetsResource(): Unit = {
+ val (fuzz, booz) = fuzzBuzzBooz
+ booz writeContent "hello, world"
+ val x = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val r = x.getResource("buzz/booz.class")
+ assertNotNull(r)
+ assertEquals("hello, world", r.slurp())
+ }
+
+ @Test
+ def afclGetsResourceFromParent(): Unit = {
+ val (fuzz, booz) = fuzzBuzzBooz
+ val (fuzz_, booz_) = fuzzBuzzBooz
+ booz writeContent "hello, world"
+ booz_ writeContent "hello, world_"
+ val p = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val x = new AbstractFileClassLoader(fuzz_, p)
+ val r = x.getResource("buzz/booz.class")
+ assertNotNull(r)
+ assertEquals("hello, world", r.slurp())
+ }
+
+ @Test
+ def afclGetsResourceInDefaultPackage(): Unit = {
+ val fuzz = new VirtualDirectory("fuzz", None)
+ val booz = fuzz fileNamed "booz.class"
+ val bass = fuzz fileNamed "bass"
+ booz writeContent "hello, world"
+ bass writeContent "lo tone"
+ val x = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val r = x.getResource("booz.class")
+ assertNotNull(r)
+ assertEquals("hello, world", r.slurp())
+ assertEquals("lo tone", (x getResource "bass").slurp())
+ }
+
+ // SI-8843
+ @Test
+ def afclGetsResources(): Unit = {
+ val (fuzz, booz) = fuzzBuzzBooz
+ booz writeContent "hello, world"
+ val x = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val e = x.getResources("buzz/booz.class")
+ assertTrue(e.hasMoreElements)
+ assertEquals("hello, world", e.nextElement.slurp())
+ assertFalse(e.hasMoreElements)
+ }
+
+ @Test
+ def afclGetsResourcesFromParent(): Unit = {
+ val (fuzz, booz) = fuzzBuzzBooz
+ val (fuzz_, booz_) = fuzzBuzzBooz
+ booz writeContent "hello, world"
+ booz_ writeContent "hello, world_"
+ val p = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val x = new AbstractFileClassLoader(fuzz_, p)
+ val e = x.getResources("buzz/booz.class")
+ assertTrue(e.hasMoreElements)
+ assertEquals("hello, world", e.nextElement.slurp())
+ assertTrue(e.hasMoreElements)
+ assertEquals("hello, world_", e.nextElement.slurp())
+ assertFalse(e.hasMoreElements)
+ }
+
+ @Test
+ def afclGetsResourceAsStream(): Unit = {
+ val (fuzz, booz) = fuzzBuzzBooz
+ booz writeContent "hello, world"
+ val x = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val r = x.getResourceAsStream("buzz/booz.class")
+ assertNotNull(r)
+ assertEquals("hello, world", Streamable.closing(r)(is => Source.fromInputStream(is).mkString))
+ }
+
+ @Test
+ def afclGetsClassBytes(): Unit = {
+ val (fuzz, booz) = fuzzBuzzBooz
+ booz writeContent "hello, world"
+ val x = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val b = x.classBytes("buzz/booz.class")
+ assertEquals("hello, world", new String(b, UTF8.charSet))
+ }
+
+ @Test
+ def afclGetsClassBytesFromParent(): Unit = {
+ val (fuzz, booz) = fuzzBuzzBooz
+ val (fuzz_, booz_) = fuzzBuzzBooz
+ booz writeContent "hello, world"
+ booz_ writeContent "hello, world_"
+
+ val p = new AbstractFileClassLoader(fuzz, NoClassLoader)
+ val x = new AbstractFileClassLoader(fuzz_, p)
+ val b = x.classBytes("buzz/booz.class")
+ assertEquals("hello, world", new String(b, UTF8.charSet))
+ }
+}
diff --git a/test/junit/scala/tools/nsc/SampleTest.scala b/test/junit/scala/tools/nsc/SampleTest.scala
index 8e026da1ea..60bb09e98f 100644
--- a/test/junit/scala/tools/nsc/SampleTest.scala
+++ b/test/junit/scala/tools/nsc/SampleTest.scala
@@ -1,5 +1,4 @@
package scala.tools.nsc
-package test
import org.junit.Assert._
import org.junit.Test
@@ -12,6 +11,6 @@ import org.junit.runners.JUnit4
class SampleTest {
@Test
def testMath: Unit = {
- assert(2+2 == 4, "you didn't get the math right fellow")
+ assertTrue("you didn't get the math right fellow", 2 + 2 == 4)
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
index 221aad6536..2347e8288e 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
@@ -19,7 +19,7 @@ class BTypesTest {
val btypes = new BTypesFromSymbols[g.type](g)
import btypes._
- duringBackend(btypes.intializeCoreBTypes())
+ duringBackend(btypes.initializeCoreBTypes())
def classBTypeFromSymbol(sym: Symbol) = duringBackend(btypes.classBTypeFromSymbol(sym))
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
index 15bc1f427d..c1c5a71b83 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
@@ -7,6 +7,8 @@ import scala.reflect.io.VirtualDirectory
import scala.tools.asm.Opcodes
import scala.tools.asm.tree.{AbstractInsnNode, LabelNode, ClassNode, MethodNode}
import scala.tools.cmd.CommandLineParser
+import scala.tools.nsc.backend.jvm.opt.LocalOpt
+import scala.tools.nsc.settings.{MutableSettings, ScalaSettings}
import scala.tools.nsc.{Settings, Global}
import scala.tools.partest.ASMConverters
import scala.collection.JavaConverters._
@@ -76,4 +78,26 @@ object CodeGenTools {
def assertSameCode(actual: List[Instruction], expected: List[Instruction]): Unit = {
assertTrue(s"\nExpected: $expected\nActual : $actual", actual === expected)
}
+
+ def getSingleMethod(classNode: ClassNode, name: String): Method =
+ convertMethod(classNode.methods.asScala.toList.find(_.name == name).get)
+
+ def assertHandlerLabelPostions(h: ExceptionHandler, instructions: List[Instruction], startIndex: Int, endIndex: Int, handlerIndex: Int): Unit = {
+ val insVec = instructions.toVector
+ assertTrue(h.start == insVec(startIndex) && h.end == insVec(endIndex) && h.handler == insVec(handlerIndex))
+ }
+
+ val localOpt = {
+ val settings = new MutableSettings(msg => throw new IllegalArgumentException(msg))
+ settings.processArguments(List("-Yopt:l:method"), processAll = true)
+ new LocalOpt(settings)
+ }
+
+ import scala.language.implicitConversions
+
+ implicit def aliveInstruction(ins: Instruction): (Instruction, Boolean) = (ins, true)
+
+ implicit class MortalInstruction(val ins: Instruction) extends AnyVal {
+ def dead: (Instruction, Boolean) = (ins, false)
+ }
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
index 2fb5bb8052..89900291ca 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala
@@ -10,13 +10,12 @@ import scala.tools.partest.ASMConverters._
@RunWith(classOf[JUnit4])
class DirectCompileTest {
- val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode")
+ val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:method")
@Test
def testCompile(): Unit = {
val List(("C.class", bytes)) = compile(compiler)(
- """
- |class C {
+ """class C {
| def f = 1
|}
""".stripMargin)
@@ -26,19 +25,12 @@ class DirectCompileTest {
@Test
def testCompileClasses(): Unit = {
- val List(cClass, cModuleClass) = compileClasses(compiler)(
- """
- |class C
- |object C
- """.stripMargin)
+ val List(cClass, cModuleClass) = compileClasses(compiler)("class C; object C")
assertTrue(cClass.name == "C")
assertTrue(cModuleClass.name == "C$")
- val List(dMirror, dModuleClass) = compileClasses(compiler)(
- """
- |object D
- """.stripMargin)
+ val List(dMirror, dModuleClass) = compileClasses(compiler)("object D")
assertTrue(dMirror.name == "D")
assertTrue(dModuleClass.name == "D$")
@@ -47,35 +39,35 @@ class DirectCompileTest {
@Test
def testCompileMethods(): Unit = {
val List(f, g) = compileMethods(compiler)(
- """
- |def f = 10
+ """def f = 10
|def g = f
""".stripMargin)
assertTrue(f.name == "f")
assertTrue(g.name == "g")
- assertTrue(instructionsFromMethod(f).dropNonOp ===
+ assertSameCode(instructionsFromMethod(f).dropNonOp,
List(IntOp(BIPUSH, 10), Op(IRETURN)))
- assertTrue(instructionsFromMethod(g).dropNonOp ===
- List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "f", "()I", false), Op(IRETURN)))
+ assertSameCode(instructionsFromMethod(g).dropNonOp,
+ List(VarOp(ALOAD, 0), Invoke(INVOKEVIRTUAL, "C", "f", "()I", itf = false), Op(IRETURN)))
}
@Test
def testDropNonOpAliveLabels(): Unit = {
+ // makes sure that dropNoOp doesn't drop labels that are being used
val List(f) = compileMethods(compiler)("""def f(x: Int) = if (x == 0) "a" else "b"""")
- assertTrue(instructionsFromMethod(f).dropNonOp === List(
- VarOp(ILOAD, 1),
- Op(ICONST_0),
- Jump(IF_ICMPEQ, Label(6)),
- Jump(GOTO, Label(10)),
- Label(6),
- Ldc(LDC, "a"),
- Jump(GOTO, Label(13)),
- Label(10),
- Ldc(LDC, "b"),
- Label(13),
- Op(ARETURN)
+ assertSameCode(instructionsFromMethod(f).dropLinesFrames, List(
+ Label(0),
+ VarOp(ILOAD, 1),
+ Op(ICONST_0),
+ Jump(IF_ICMPNE,
+ Label(7)),
+ Ldc(LDC, "a"),
+ Op(ARETURN),
+ Label(7),
+ Ldc(LDC, "b"),
+ Op(ARETURN),
+ Label(11)
))
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
new file mode 100644
index 0000000000..2975bd060d
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala
@@ -0,0 +1,95 @@
+package scala.tools.nsc
+package backend.jvm
+package opt
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes._
+import org.junit.Assert._
+
+import scala.tools.nsc.backend.jvm.BTypes.InternalName
+import scala.tools.testing.AssertUtil._
+
+import CodeGenTools._
+import scala.tools.partest.ASMConverters
+import ASMConverters._
+
+import scala.collection.convert.decorateAsScala._
+
+@RunWith(classOf[JUnit4])
+class BTypesFromClassfileTest {
+ val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode")
+
+ import compiler._
+ import definitions._
+ import genBCode.bTypes
+ import bTypes._
+
+ def duringBackend[T](f: => T) = compiler.exitingDelambdafy(f)
+
+ val run = new compiler.Run() // initializes some of the compiler
+ duringBackend(bTypes.initializeCoreBTypes())
+
+ def clearCache() = bTypes.classBTypeFromInternalName.clear()
+
+ def sameBType(fromSym: ClassBType, fromClassfile: ClassBType, checked: Set[InternalName] = Set.empty): Set[InternalName] = {
+ if (checked(fromSym.internalName)) checked
+ else {
+ assert(fromSym == fromClassfile, s"$fromSym != $fromClassfile")
+ sameInfo(fromSym.info, fromClassfile.info, checked + fromSym.internalName)
+ }
+ }
+
+ def sameBTypes(fromSyms: Iterable[ClassBType], fromClassfiles: Iterable[ClassBType], checked: Set[InternalName]): Set[InternalName] = {
+ assert(fromSyms.size == fromClassfiles.size, s"\n$fromSyms\n$fromClassfiles")
+ (fromSyms, fromClassfiles).zipped.foldLeft(checked) {
+ case (chk, (fromSym, fromClassfile)) => sameBType(fromSym, fromClassfile, chk)
+ }
+ }
+
+ def sameInfo(fromSym: ClassInfo, fromClassfile: ClassInfo, checked: Set[InternalName]): Set[InternalName] = {
+ assert({
+ // Nested class symbols can undergo makeNotPrivate (ExplicitOuter). But this is only applied
+ // for symbols of class symbols that are being compiled, not those read from a pickle.
+ // So a class may be public in bytecode, but the symbol still says private.
+ if (fromSym.nestedInfo.isEmpty) fromSym.flags == fromClassfile.flags
+ else (fromSym.flags | ACC_PRIVATE | ACC_PUBLIC) == (fromClassfile.flags | ACC_PRIVATE | ACC_PUBLIC)
+ }, s"class flags differ\n$fromSym\n$fromClassfile")
+
+ val chk1 = sameBTypes(fromSym.superClass, fromClassfile.superClass, checked)
+
+ val chk2 = sameBTypes(fromSym.interfaces, fromClassfile.interfaces, chk1)
+
+ // The fromSym info has only member classes, no local or anonymous. The symbol is read from the
+ // Scala pickle data and only member classes are created / entered.
+ // (This is different for symbols that are being compiled, there flatten will enter all local
+ // and anonymous classes as members of the outer class. But not for unpickled symbols).
+ // The fromClassfile info has all nested classes, including anonymous and local. So we filter
+ // them out: member classes are identified by having the `outerName` defined.
+ val memberClassesFromClassfile = fromClassfile.nestedClasses.filter(_.info.nestedInfo.get.outerName.isDefined)
+ // Sorting is required: the backend sorts all InnerClass entries by internalName before writing
+ // them to the classfile (to make it deterministic: the entries are collected in a Set during
+ // code generation).
+ val chk3 = sameBTypes(fromSym.nestedClasses.sortBy(_.internalName), memberClassesFromClassfile.sortBy(_.internalName), chk2)
+ sameBTypes(fromSym.nestedInfo.map(_.enclosingClass), fromClassfile.nestedInfo.map(_.enclosingClass), chk3)
+ }
+
+ def check(classSym: Symbol): Unit = duringBackend {
+ clearCache()
+ val fromSymbol = classBTypeFromSymbol(classSym)
+ clearCache()
+ val fromClassfile = bTypes.classBTypeFromParsedClassfile(fromSymbol.internalName)
+ sameBType(fromSymbol, fromClassfile)
+ }
+
+ @Test
+ def compareClassBTypes(): Unit = {
+ // Note that not only these classes are tested, but also all their parents and all nested
+ // classes in their InnerClass attributes.
+ check(ObjectClass)
+ check(JavaNumberClass)
+ check(ConsClass)
+ check(ListModule.moduleClass)
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala
new file mode 100644
index 0000000000..fc748196d0
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala
@@ -0,0 +1,80 @@
+package scala.tools.nsc
+package backend.jvm
+package opt
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes._
+import org.junit.Assert._
+
+import CodeGenTools._
+import scala.tools.partest.ASMConverters
+import ASMConverters._
+
+@RunWith(classOf[JUnit4])
+class CompactLocalVariablesTest {
+
+ // recurse-unreachable-jumps is required for eliminating catch blocks, in the first dce round they
+ // are still live.only after eliminating the empty handler the catch blocks become unreachable.
+ val methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code,recurse-unreachable-jumps,compact-locals")
+ val noCompactVarsCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code,recurse-unreachable-jumps")
+
+ @Test
+ def compactUnused(): Unit = {
+ val code =
+ """def f: Double = {
+ | try { }
+ | catch {
+ | case _: Throwable =>
+ | // eliminated by dce
+ | val i = 1
+ | val d = 1d
+ | val f = 1f
+ | val l = 1l
+ | }
+ |
+ | val i = 1 // variable index 1 (it's an instance method, so at index 0 we have `this`)
+ | val d = 1d // 2,3
+ | val f = 1f // 4
+ | val l = 1l // 5,6
+ |
+ | try { }
+ | catch {
+ | case _: Throwable =>
+ | // eliminated by dce
+ | val i = 1
+ | val d = 1d
+ | val f = 1f
+ | val l = 1l
+ | }
+ |
+ | val ii = 1 // 7
+ | val dd = 1d // 8,9
+ | val ff = 1f // 10
+ | val ll = 1l // 11,12
+ |
+ | i + ii + d + dd + f + ff + l + ll
+ |}
+ |""".stripMargin
+
+ val List(noCompact) = compileMethods(noCompactVarsCompiler)(code)
+ val List(withCompact) = compileMethods(methodOptCompiler)(code)
+
+ // code is the same, except for local var indices
+ assertTrue(noCompact.instructions.size == withCompact.instructions.size)
+
+ val varOpSlots = convertMethod(withCompact).instructions collect {
+ case VarOp(_, v) => v
+ }
+ assertTrue(varOpSlots.toString, varOpSlots == List(1, 2, 4, 5, 7, 8, 10, 11, // stores
+ 1, 7, 2, 8, 4, 10, 5, 11)) // loads
+
+ // the local variables descriptor table is cleaned up to remove stale entries after dce,
+ // also when the slots are not compacted
+ assertTrue(noCompact.localVariables.size == withCompact.localVariables.size)
+
+ assertTrue(noCompact.maxLocals == 25)
+ assertTrue(withCompact.maxLocals == 13)
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
index 57fa1a7b66..7d83c54b5b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
@@ -26,7 +26,7 @@ class EmptyExceptionHandlersTest {
Op(RETURN)
)
assertTrue(convertMethod(asmMethod).handlers.length == 1)
- LocalOpt.removeEmptyExceptionHandlers(asmMethod)
+ localOpt.removeEmptyExceptionHandlers(asmMethod)
assertTrue(convertMethod(asmMethod).handlers.isEmpty)
}
@@ -35,12 +35,8 @@ class EmptyExceptionHandlersTest {
val handlers = List(ExceptionHandler(Label(1), Label(2), Label(2), Some(exceptionDescriptor)))
val asmMethod = genMethod(handlers = handlers)(
Label(1), // nops only
- Op(NOP),
- Op(NOP),
Jump(GOTO, Label(3)),
- Op(NOP),
Label(3),
- Op(NOP),
Jump(GOTO, Label(4)),
Label(2), // handler
@@ -51,7 +47,7 @@ class EmptyExceptionHandlersTest {
Op(RETURN)
)
assertTrue(convertMethod(asmMethod).handlers.length == 1)
- LocalOpt.removeEmptyExceptionHandlers(asmMethod)
+ localOpt.removeEmptyExceptionHandlers(asmMethod)
assertTrue(convertMethod(asmMethod).handlers.isEmpty)
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
new file mode 100644
index 0000000000..8c0168826e
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
@@ -0,0 +1,99 @@
+package scala.tools.nsc
+package backend.jvm
+package opt
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes._
+import org.junit.Assert._
+import scala.tools.testing.AssertUtil._
+
+import CodeGenTools._
+import scala.tools.partest.ASMConverters
+import ASMConverters._
+
+@RunWith(classOf[JUnit4])
+class EmptyLabelsAndLineNumbersTest {
+ @Test
+ def removeEmptyLineNumbers(): Unit = {
+ val ops = List[(Instruction, Boolean)](
+ Label(1),
+ LineNumber(1, Label(1)),
+ Label(2),
+ Label(3),
+ Op(RETURN),
+
+ Label(4),
+ LineNumber(4, Label(4)).dead,
+ LineNumber(5, Label(4)),
+ Op(RETURN),
+
+ Label(5),
+ LineNumber(6, Label(5)).dead,
+ Label(6),
+ Label(7),
+ LineNumber(7, Label(7)),
+ Op(RETURN),
+
+ Label(9),
+ LineNumber(8, Label(9)).dead,
+ Label(10)
+ )
+
+ val method = genMethod()(ops.map(_._1): _*)
+ assertTrue(localOpt.removeEmptyLineNumbers(method))
+ assertSameCode(instructionsFromMethod(method), ops.filter(_._2).map(_._1))
+ }
+
+ @Test
+ def badlyLocatedLineNumbers(): Unit = {
+ def t(ops: Instruction*) =
+ assertThrows[AssertionError](localOpt.removeEmptyLineNumbers(genMethod()(ops: _*)))
+
+ // line numbers have to be right after their referenced label node
+ t(LineNumber(0, Label(1)), Label(1))
+ t(Label(0), Label(1), LineNumber(0, Label(0)))
+ }
+
+ @Test
+ def removeEmptyLabels(): Unit = {
+ val handler = List(ExceptionHandler(Label(4), Label(5), Label(6), Some("java/lang/Throwable")))
+ def ops(target1: Int, target2: Int, target3: Int, target4: Int, target5: Int, target6: Int) = List[(Instruction, Boolean)](
+ Label(1),
+ Label(2).dead,
+ Label(3).dead,
+ LineNumber(3, Label(target1)),
+ VarOp(ILOAD, 1),
+ Jump(IFGE, Label(target2)),
+
+ Label(4),
+ Label(5).dead,
+ Label(6).dead,
+ VarOp(ILOAD, 2),
+ Jump(IFGE, Label(target3)),
+
+ Label(7),
+ Label(8).dead,
+ Label(9).dead,
+ Op(RETURN),
+
+ LookupSwitch(LOOKUPSWITCH, Label(target4), List(1,2), List(Label(target4), Label(target5))),
+ TableSwitch(TABLESWITCH, 1, 2, Label(target4), List(Label(target4), Label(target5))),
+
+ Label(10),
+ LineNumber(10, Label(10)),
+ Label(11).dead,
+ LineNumber(12, Label(target6))
+ )
+
+ val method = genMethod(handlers = handler)(ops(2, 3, 8, 8, 9, 11).map(_._1): _*)
+ assertTrue(localOpt.removeEmptyLabelNodes(method))
+ val m = convertMethod(method)
+ assertSameCode(m.instructions, ops(1, 1, 7, 7, 7, 10).filter(_._2).map(_._1))
+ assertTrue(m.handlers match {
+ case List(ExceptionHandler(Label(4), Label(4), Label(4), _)) => true
+ case _ => false
+ })
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala
new file mode 100644
index 0000000000..5430e33d6c
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala
@@ -0,0 +1,83 @@
+package scala.tools.nsc
+package backend.jvm
+package opt
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes._
+import org.junit.Assert._
+
+import scala.tools.testing.AssertUtil._
+
+import CodeGenTools._
+import scala.tools.partest.ASMConverters
+import ASMConverters._
+
+@RunWith(classOf[JUnit4])
+class MethodLevelOpts {
+ val methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method")
+
+ def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1))
+
+ @Test
+ def eliminateEmptyTry(): Unit = {
+ val code = "def f = { try {} catch { case _: Throwable => 0; () }; 1 }"
+ assertSameCode(singleMethodInstructions(methodOptCompiler)(code), wrapInDefault(Op(ICONST_1), Op(IRETURN)))
+ }
+
+ @Test
+ def cannotEliminateLoadBoxedUnit(): Unit = {
+ // the compiler inserts a boxed into the try block. it's therefore non-empty (and live) and not eliminated.
+ val code = "def f = { try {} catch { case _: Throwable => 0 }; 1 }"
+ val m = singleMethod(methodOptCompiler)(code)
+ assertTrue(m.handlers.length == 1)
+ assertSameCode(m.instructions.take(3), List(Label(0), LineNumber(1, Label(0)), Field(GETSTATIC, "scala/runtime/BoxedUnit", "UNIT", "Lscala/runtime/BoxedUnit;")))
+ }
+
+ @Test
+ def inlineThrowInCatchNotTry(): Unit = {
+ // the try block does not contain the `ATHROW` instruction, but in the catch block, `ATHROW` is inlined
+ val code = "def f(e: Exception) = throw { try e catch { case _: Throwable => e } }"
+ val m = singleMethod(methodOptCompiler)(code)
+ assertHandlerLabelPostions(m.handlers.head, m.instructions, 0, 3, 5)
+ assertSameCode(m.instructions,
+ wrapInDefault(VarOp(ALOAD, 1), Label(3), Op(ATHROW), Label(5), FrameEntry(4, List(), List("java/lang/Throwable")), Op(POP), VarOp(ALOAD, 1), Op(ATHROW))
+ )
+ }
+
+ @Test
+ def inlineReturnInCachtNotTry(): Unit = {
+ val code = "def f: Int = return { try 1 catch { case _: Throwable => 2 } }"
+ // cannot inline the IRETURN into the try block (because RETURN may throw IllegalMonitorState)
+ val m = singleMethod(methodOptCompiler)(code)
+ assertHandlerLabelPostions(m.handlers.head, m.instructions, 0, 3, 5)
+ assertSameCode(m.instructions,
+ wrapInDefault(Op(ICONST_1), Label(3), Op(IRETURN), Label(5), FrameEntry(4, List(), List("java/lang/Throwable")), Op(POP), Op(ICONST_2), Op(IRETURN)))
+ }
+
+ @Test
+ def simplifyJumpsInTryCatchFinally(): Unit = {
+ val code =
+ """def f: Int =
+ | try {
+ | return 1
+ | } catch {
+ | case _: Throwable =>
+ | return 2
+ | } finally {
+ | return 2
+ | // dead
+ | val x = try 10 catch { case _: Throwable => 11 }
+ | println(x)
+ | }
+ """.stripMargin
+ val m = singleMethod(methodOptCompiler)(code)
+ assertTrue(m.handlers.length == 2)
+ assertSameCode(m.instructions.dropNonOp, // drop line numbers and labels that are only used by line numbers
+
+ // one single label left :-)
+ List(Op(ICONST_1), VarOp(ISTORE, 2), Jump(GOTO, Label(20)), Op(POP), Op(ICONST_2), VarOp(ISTORE, 2), Jump(GOTO, Label(20)), VarOp(ASTORE, 3), Op(ICONST_2), Op(IRETURN), Label(20), Op(ICONST_2), Op(IRETURN))
+ )
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala
new file mode 100644
index 0000000000..360fa1d23d
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala
@@ -0,0 +1,221 @@
+package scala.tools.nsc
+package backend.jvm
+package opt
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import scala.tools.asm.Opcodes._
+import org.junit.Assert._
+
+import CodeGenTools._
+import scala.tools.partest.ASMConverters
+import ASMConverters._
+
+@RunWith(classOf[JUnit4])
+class SimplifyJumpsTest {
+ @Test
+ def simpleGotoReturn(): Unit = {
+ val ops = List(
+ Jump(GOTO, Label(2)), // replaced by RETURN
+ Op(ICONST_1), // need some code, otherwise removeJumpToSuccessor kicks in
+ Op(POP),
+ Label(1), // multiple labels OK
+ Label(2),
+ Label(3),
+ Op(RETURN)
+ )
+ val method = genMethod()(ops: _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), Op(RETURN) :: ops.tail)
+ }
+
+ @Test
+ def simpleGotoThrow(): Unit = {
+ val rest = List(
+ Op(ICONST_1), // need some code, otherwise removeJumpToSuccessor kicks in
+ Op(POP),
+ Label(1),
+ Label(2),
+ Label(3),
+ Op(ATHROW)
+ )
+ val method = genMethod()(
+ Op(ACONST_NULL) ::
+ Jump(GOTO, Label(2)) :: // replaced by ATHROW
+ rest: _*
+ )
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), Op(ACONST_NULL) :: Op(ATHROW) :: rest)
+ }
+
+ @Test
+ def gotoThrowInTry(): Unit = {
+ val handler = List(ExceptionHandler(Label(1), Label(2), Label(4), Some("java/lang/Throwable")))
+ val initialInstrs = List(
+ Label(1),
+ Op(ACONST_NULL),
+ Jump(GOTO, Label(3)), // not by ATHROW (would move the ATHROW into a try block)
+ Label(2),
+ Op(ICONST_1), // need some code, otherwise removeJumpToSuccessor kicks in
+ Op(POP),
+ Label(3),
+ Op(ATHROW),
+ Label(4),
+ Op(POP),
+ Op(RETURN)
+ )
+ val method = genMethod(handlers = handler)(initialInstrs: _*)
+ assertFalse(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), initialInstrs)
+
+ val optMethod = genMethod()(initialInstrs: _*) // no handler
+ assertTrue(localOpt.simplifyJumps(optMethod))
+ assertSameCode(instructionsFromMethod(optMethod).take(3), List(Label(1), Op(ACONST_NULL), Op(ATHROW)))
+ }
+
+ @Test
+ def simplifyBranchOverGoto(): Unit = {
+ val begin = List(
+ VarOp(ILOAD, 1),
+ Jump(IFGE, Label(2))
+ )
+ val rest = List(
+ Jump(GOTO, Label(3)),
+ Label(11), // other labels here are allowed
+ Label(2),
+ VarOp(ILOAD, 1),
+ Op(RETURN),
+ Label(3),
+ VarOp(ILOAD, 1),
+ Op(IRETURN)
+ )
+ val method = genMethod()(begin ::: rest: _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(
+ instructionsFromMethod(method),
+ List(VarOp(ILOAD, 1), Jump(IFLT, Label(3))) ::: rest.tail )
+
+ // no label allowed between begin and rest. if there's another label, then there could be a
+ // branch that label. eliminating the GOTO would change the behavior.
+ val nonOptMethod = genMethod()(begin ::: Label(22) :: rest: _*)
+ assertFalse(localOpt.simplifyJumps(nonOptMethod))
+ }
+
+ @Test
+ def ensureGotoRemoved(): Unit = {
+ def code(jumps: Instruction*) = List(
+ VarOp(ILOAD, 1)) ::: jumps.toList ::: List(
+ Label(2),
+
+ Op(RETURN),
+ Label(3),
+ Op(RETURN)
+ )
+
+ // ensures that the goto is safely removed. ASM supports removing while iterating, but not the
+ // next element of the current. Here, the current is the IFGE, the next is the GOTO.
+ val method = genMethod()(code(Jump(IFGE, Label(2)), Jump(GOTO, Label(3))): _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), code(Jump(IFLT, Label(3))))
+ }
+
+ @Test
+ def removeJumpToSuccessor(): Unit = {
+ val ops = List(
+ Jump(GOTO, Label(1)),
+ Label(11),
+ Label(1),
+ Label(2),
+ VarOp(ILOAD, 1),
+ Op(IRETURN)
+ )
+ val method = genMethod()(ops: _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), ops.tail)
+ }
+
+ @Test
+ def collapseJumpChains(): Unit = {
+ def ops(target1: Int, target2: Int, target3: Int) = List(
+ VarOp(ILOAD, 1),
+ Jump(IFGE, Label(target1)), // initially 1, then 3
+ VarOp(ILOAD, 1),
+ Op(IRETURN),
+
+ Label(2),
+ Jump(GOTO, Label(target3)),
+
+ Label(1),
+ Jump(GOTO, Label(target2)), // initially 2, then 3
+
+ VarOp(ILOAD, 1), // some code to prevent jumpToSuccessor optimization (once target2 is replaced by 3)
+ Op(RETURN),
+
+ Label(3),
+ VarOp(ILOAD, 1),
+ Op(IRETURN)
+ )
+ val method = genMethod()(ops(1, 2, 3): _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), ops(3, 3, 3))
+ }
+
+ @Test
+ def collapseJumpChainLoop(): Unit = {
+ def ops(target: Int) = List(
+ VarOp(ILOAD, 1),
+ Jump(IFGE, Label(target)),
+
+ Label(4),
+ Jump(GOTO, Label(3)),
+
+ VarOp(ILOAD, 1), // some code to prevent jumpToSuccessor (label 3)
+ Op(IRETURN),
+
+ Label(3),
+ Jump(GOTO, Label(4)),
+
+ Label(2),
+ Jump(GOTO, Label(3))
+ )
+
+ val method = genMethod()(ops(2): _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), ops(3))
+ }
+
+ @Test
+ def simplifyThenElseSameTarget(): Unit = {
+ def ops(jumpOp: Instruction) = List(
+ VarOp(ILOAD, 1),
+ jumpOp,
+ Label(2),
+ Jump(GOTO, Label(1)),
+
+ VarOp(ILOAD, 1), // some code to prevent jumpToSuccessor (label 1)
+ Op(IRETURN),
+
+ Label(1),
+ VarOp(ILOAD, 1),
+ Op(IRETURN)
+ )
+
+ val method = genMethod()(ops(Jump(IFGE, Label(1))): _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), ops(Op(POP)))
+ }
+
+ @Test
+ def thenElseSameTargetLoop(): Unit = {
+ def ops(br: List[Instruction]) = List(
+ VarOp(ILOAD, 1),
+ VarOp(ILOAD, 2)) ::: br ::: List(
+ Label(1),
+ Jump(GOTO, Label(1))
+ )
+ val method = genMethod()(ops(List(Jump(IF_ICMPGE, Label(1)))): _*)
+ assertTrue(localOpt.simplifyJumps(method))
+ assertSameCode(instructionsFromMethod(method), ops(List(Op(POP), Op(POP))))
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
index a3bd7ae6fe..4a45dd9138 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
@@ -16,12 +16,20 @@ import ASMConverters._
@RunWith(classOf[JUnit4])
class UnreachableCodeTest {
- import UnreachableCodeTest._
+
+ def assertEliminateDead(code: (Instruction, Boolean)*): Unit = {
+ val method = genMethod()(code.map(_._1): _*)
+ localOpt.removeUnreachableCodeImpl(method, "C")
+ val nonEliminated = instructionsFromMethod(method)
+ val expectedLive = code.filter(_._2).map(_._1).toList
+ assertSameCode(nonEliminated, expectedLive)
+ }
// jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks,
// see comment in BCodeBodyBuilder
- val dceCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code")
- val noOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:none")
+ val methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method")
+ val dceCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code")
+ val noOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:none")
// jvm-1.5 disables computing stack map frames, and it emits dead code as-is.
val noOptNoFramesCompiler = newCompiler(extraArgs = "-target:jvm-1.5 -Ybackend:GenBCode -Yopt:l:none")
@@ -48,8 +56,8 @@ class UnreachableCodeTest {
@Test
def eliminateNop(): Unit = {
assertEliminateDead(
- // not dead, since visited by data flow analysis. need a different opt to eliminate it.
- Op(NOP),
+ // reachable, but removed anyway.
+ Op(NOP).dead,
Op(RETURN),
Op(NOP).dead
)
@@ -136,28 +144,31 @@ class UnreachableCodeTest {
@Test
def eliminateDeadCatchBlocks(): Unit = {
+ // the Label(1) is live: it's used in the local variable descriptor table (local variable "this" has a range from 0 to 1).
+ def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1))
+
val code = "def f: Int = { return 0; try { 1 } catch { case _: Exception => 2 } }"
- assertSameCode(singleMethodInstructions(dceCompiler)(code).dropNonOp,
- List(Op(ICONST_0), Op(IRETURN)))
+ val m = singleMethod(dceCompiler)(code)
+ assertTrue(m.handlers.isEmpty) // redundant (if code is gone, handler is gone), but done once here for extra safety
+ assertSameCode(m.instructions,
+ wrapInDefault(Op(ICONST_0), Op(IRETURN)))
val code2 = "def f: Unit = { try { } catch { case _: Exception => () }; () }"
- // DCE only removes dead basic blocks, but not NOPs, and also not useless jumps
- assertSameCode(singleMethodInstructions(dceCompiler)(code2).dropNonOp,
- List(Op(NOP), Jump(GOTO, Label(33)), Label(33), Op(RETURN)))
+ // requires fixpoint optimization of methodOptCompiler (dce alone is not enough): first the handler is eliminated, then it's dead catch block.
+ assertSameCode(singleMethodInstructions(methodOptCompiler)(code2), wrapInDefault(Op(RETURN)))
val code3 = "def f: Unit = { try { } catch { case _: Exception => try { } catch { case _: Exception => () } }; () }"
- assertSameCode(singleMethodInstructions(dceCompiler)(code3).dropNonOp,
- List(Op(NOP), Jump(GOTO, Label(33)), Label(33), Op(RETURN)))
+ assertSameCode(singleMethodInstructions(methodOptCompiler)(code3), wrapInDefault(Op(RETURN)))
+ // this example requires two iterations to get rid of the outer handler.
+ // the first iteration of DCE cannot remove the inner handler. then the inner (empty) handler is removed.
+ // then the second iteration of DCE removes the inner catch block, and then the outer handler is removed.
val code4 = "def f: Unit = { try { try { } catch { case _: Exception => () } } catch { case _: Exception => () }; () }"
- assertSameCode(singleMethodInstructions(dceCompiler)(code4).dropNonOp,
- List(Op(NOP), Jump(GOTO, Label(4)), Label(4), Jump(GOTO, Label(7)), Label(7), Op(RETURN)))
+ assertSameCode(singleMethodInstructions(methodOptCompiler)(code4), wrapInDefault(Op(RETURN)))
}
@Test // test the dce-testing tools
def metaTest(): Unit = {
- assertEliminateDead() // no instructions
-
assertThrows[AssertionError](
assertEliminateDead(Op(RETURN).dead),
_.contains("Expected: List()\nActual : List(Op(RETURN))")
@@ -198,20 +209,3 @@ class UnreachableCodeTest {
List(FrameEntry(F_FULL, List(INTEGER, DOUBLE, Label(1)), List("java/lang/Object", Label(3))), Label(1), Label(3)))
}
}
-
-object UnreachableCodeTest {
- import scala.language.implicitConversions
- implicit def aliveInstruction(ins: Instruction): (Instruction, Boolean) = (ins, true)
-
- implicit class MortalInstruction(val ins: Instruction) extends AnyVal {
- def dead: (Instruction, Boolean) = (ins, false)
- }
-
- def assertEliminateDead(code: (Instruction, Boolean)*): Unit = {
- val cls = wrapInClass(genMethod()(code.map(_._1): _*))
- LocalOpt.removeUnreachableCode(cls)
- val nonEliminated = instructionsFromMethod(cls.methods.get(0))
- val expectedLive = code.filter(_._2).map(_._1).toList
- assertSameCode(nonEliminated, expectedLive)
- }
-}
diff --git a/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala b/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala
new file mode 100644
index 0000000000..9a004d5e0e
--- /dev/null
+++ b/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.classpath
+
+import java.net.URL
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import scala.reflect.io.VirtualFile
+import scala.tools.nsc.io.AbstractFile
+
+/**
+ * Tests whether AggregateFlatClassPath returns correct entries taken from
+ * cp instances used during creating it and whether it preserves the ordering
+ * (in the case of the repeated entry for a class or a source it returns the first one).
+ */
+@RunWith(classOf[JUnit4])
+class AggregateFlatClassPathTest {
+
+ private class TestFlatClassPath extends FlatClassPath {
+ override def packages(inPackage: String): Seq[PackageEntry] = unsupported
+ override def sources(inPackage: String): Seq[SourceFileEntry] = unsupported
+ override def classes(inPackage: String): Seq[ClassFileEntry] = unsupported
+
+ override def list(inPackage: String): FlatClassPathEntries = unsupported
+ override def findClassFile(name: String): Option[AbstractFile] = unsupported
+
+ override def asClassPathStrings: Seq[String] = unsupported
+ override def asSourcePathString: String = unsupported
+ override def asURLs: Seq[URL] = unsupported
+ }
+
+ private case class TestClassPath(virtualPath: String, classesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+
+ override def classes(inPackage: String): Seq[ClassFileEntry] =
+ for {
+ entriesWrapper <- classesInPackage if entriesWrapper.inPackage == inPackage
+ name <- entriesWrapper.names
+ } yield classFileEntry(virtualPath, inPackage, name)
+
+ override def sources(inPackage: String): Seq[SourceFileEntry] = Nil
+
+ // we'll ignore packages
+ override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, classes(inPackage))
+ }
+
+ private case class TestSourcePath(virtualPath: String, sourcesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+
+ override def sources(inPackage: String): Seq[SourceFileEntry] =
+ for {
+ entriesWrapper <- sourcesInPackage if entriesWrapper.inPackage == inPackage
+ name <- entriesWrapper.names
+ } yield sourceFileEntry(virtualPath, inPackage, name)
+
+ override def classes(inPackage: String): Seq[ClassFileEntry] = Nil
+
+ // we'll ignore packages
+ override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, sources(inPackage))
+ }
+
+ private case class EntryNamesInPackage(inPackage: String)(val names: String*)
+
+ private val dir1 = "./dir1"
+ private val dir2 = "./dir2"
+ private val dir3 = "./dir3"
+ private val dir4 = ""
+
+ private val pkg1 = "pkg1"
+ private val pkg2 = "pkg2"
+ private val pkg3 = "pkg1.nested"
+ private val nonexistingPkg = "nonexisting"
+
+ private def unsupported = throw new UnsupportedOperationException
+
+ private def classFileEntry(pathPrefix: String, inPackage: String, fileName: String) =
+ ClassFileEntryImpl(classFile(pathPrefix, inPackage, fileName))
+
+ private def sourceFileEntry(pathPrefix: String, inPackage: String, fileName: String) =
+ SourceFileEntryImpl(sourceFile(pathPrefix, inPackage, fileName))
+
+ private def classFile(pathPrefix: String, inPackage: String, fileName: String) =
+ virtualFile(pathPrefix, inPackage, fileName, ".class")
+
+ private def sourceFile(pathPrefix: String, inPackage: String, fileName: String) =
+ virtualFile(pathPrefix, inPackage, fileName, ".scala")
+
+ private def virtualFile(pathPrefix: String, inPackage: String, fileName: String, extension: String) = {
+ val packageDirs =
+ if (inPackage == FlatClassPath.RootPackage) ""
+ else inPackage.split('.').mkString("/", "/", "")
+ new VirtualFile(fileName + extension, s"$pathPrefix$packageDirs/$fileName$extension")
+ }
+
+ private def createDefaultTestClasspath() = {
+ val partialClassPaths = Seq(TestSourcePath(dir1, EntryNamesInPackage(pkg1)("F", "A", "G")),
+ TestClassPath(dir2, EntryNamesInPackage(pkg1)("C", "B", "A"), EntryNamesInPackage(pkg2)("D", "A", "E")),
+ TestClassPath(dir3, EntryNamesInPackage(pkg1)("A", "D", "F")),
+ TestSourcePath(dir4, EntryNamesInPackage(pkg2)("A", "H", "I"), EntryNamesInPackage(pkg1)("A")),
+ TestSourcePath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
+ )
+
+ AggregateFlatClassPath(partialClassPaths)
+ }
+
+ @Test
+ def testGettingPackages: Unit = {
+ case class ClassPathWithPackages(packagesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ override def packages(inPackage: String): Seq[PackageEntry] =
+ packagesInPackage.find(_.inPackage == inPackage).map(_.names).getOrElse(Nil) map PackageEntryImpl
+ }
+
+ val partialClassPaths = Seq(ClassPathWithPackages(EntryNamesInPackage(pkg1)("pkg1.a", "pkg1.d", "pkg1.f")),
+ ClassPathWithPackages(EntryNamesInPackage(pkg1)("pkg1.c", "pkg1.b", "pkg1.a"),
+ EntryNamesInPackage(pkg2)("pkg2.d", "pkg2.a", "pkg2.e"))
+ )
+ val cp = AggregateFlatClassPath(partialClassPaths)
+
+ val packagesInPkg1 = Seq("pkg1.a", "pkg1.d", "pkg1.f", "pkg1.c", "pkg1.b")
+ assertEquals(packagesInPkg1, cp.packages(pkg1).map(_.name))
+
+ val packagesInPkg2 = Seq("pkg2.d", "pkg2.a", "pkg2.e")
+ assertEquals(packagesInPkg2, cp.packages(pkg2).map(_.name))
+
+ assertEquals(Seq.empty, cp.packages(nonexistingPkg))
+ }
+
+ @Test
+ def testGettingClasses: Unit = {
+ val cp = createDefaultTestClasspath()
+
+ val classesInPkg1 = Seq(classFileEntry(dir2, pkg1, "C"),
+ classFileEntry(dir2, pkg1, "B"),
+ classFileEntry(dir2, pkg1, "A"),
+ classFileEntry(dir3, pkg1, "D"),
+ classFileEntry(dir3, pkg1, "F")
+ )
+ assertEquals(classesInPkg1, cp.classes(pkg1))
+
+ val classesInPkg2 = Seq(classFileEntry(dir2, pkg2, "D"),
+ classFileEntry(dir2, pkg2, "A"),
+ classFileEntry(dir2, pkg2, "E")
+ )
+ assertEquals(classesInPkg2, cp.classes(pkg2))
+
+ assertEquals(Seq.empty, cp.classes(pkg3))
+ assertEquals(Seq.empty, cp.classes(nonexistingPkg))
+ }
+
+ @Test
+ def testGettingSources: Unit = {
+ val partialClassPaths = Seq(TestClassPath(dir1, EntryNamesInPackage(pkg1)("F", "A", "G")),
+ TestSourcePath(dir2, EntryNamesInPackage(pkg1)("C", "B", "A"), EntryNamesInPackage(pkg2)("D", "A", "E")),
+ TestSourcePath(dir3, EntryNamesInPackage(pkg1)("A", "D", "F")),
+ TestClassPath(dir4, EntryNamesInPackage(pkg2)("A", "H", "I")),
+ TestClassPath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
+ )
+ val cp = AggregateFlatClassPath(partialClassPaths)
+
+ val sourcesInPkg1 = Seq(sourceFileEntry(dir2, pkg1, "C"),
+ sourceFileEntry(dir2, pkg1, "B"),
+ sourceFileEntry(dir2, pkg1, "A"),
+ sourceFileEntry(dir3, pkg1, "D"),
+ sourceFileEntry(dir3, pkg1, "F")
+ )
+ assertEquals(sourcesInPkg1, cp.sources(pkg1))
+
+ val sourcesInPkg2 = Seq(sourceFileEntry(dir2, pkg2, "D"),
+ sourceFileEntry(dir2, pkg2, "A"),
+ sourceFileEntry(dir2, pkg2, "E")
+ )
+ assertEquals(sourcesInPkg2, cp.sources(pkg2))
+
+ assertEquals(Seq.empty, cp.sources(pkg3))
+ assertEquals(Seq.empty, cp.sources(nonexistingPkg))
+ }
+
+ @Test
+ def testList: Unit = {
+ val cp = createDefaultTestClasspath()
+
+ val classesAndSourcesInPkg1 = Seq(
+ ClassAndSourceFilesEntry(classFile(dir3, pkg1, "F"), sourceFile(dir1, pkg1, "F")),
+ ClassAndSourceFilesEntry(classFile(dir2, pkg1, "A"), sourceFile(dir1, pkg1, "A")),
+ sourceFileEntry(dir1, pkg1, "G"),
+ classFileEntry(dir2, pkg1, "C"),
+ classFileEntry(dir2, pkg1, "B"),
+ classFileEntry(dir3, pkg1, "D")
+ )
+ assertEquals(classesAndSourcesInPkg1, cp.list(pkg1).classesAndSources)
+
+ assertEquals(FlatClassPathEntries(Nil, Nil), cp.list(nonexistingPkg))
+ }
+
+ @Test
+ def testFindClass: Unit = {
+ val cp = createDefaultTestClasspath()
+
+ assertEquals(
+ Some(ClassAndSourceFilesEntry(classFile(dir2, pkg1, "A"), sourceFile(dir1, pkg1, "A"))),
+ cp.findClass(s"$pkg1.A")
+ )
+ assertEquals(Some(classFileEntry(dir3, pkg1, "D")), cp.findClass(s"$pkg1.D"))
+ assertEquals(Some(sourceFileEntry(dir2, pkg3, "L")), cp.findClass(s"$pkg3.L"))
+ assertEquals(None, cp.findClass("Nonexisting"))
+ }
+}
diff --git a/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala b/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala
new file mode 100644
index 0000000000..a37ba31b31
--- /dev/null
+++ b/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.classpath
+
+import java.io.File
+import org.junit.Assert._
+import org.junit._
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import scala.annotation.tailrec
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.util.ClassPath
+import scala.tools.nsc.Settings
+import scala.tools.util.FlatClassPathResolver
+import scala.tools.util.PathResolver
+
+@RunWith(classOf[JUnit4])
+class FlatClassPathResolverTest {
+
+ val tempDir = new TemporaryFolder()
+
+ private val packagesToTest = List(FlatClassPath.RootPackage, "scala", "scala.reflect", "scala.reflect.io")
+ private val classFilesToFind = List("scala.tools.util.FlatClassPathResolver",
+ "scala.reflect.io.AbstractFile",
+ "scala.collection.immutable.List",
+ "scala.Option",
+ "scala.collection.immutable.Vector",
+ "scala.util.hashing.MurmurHash3",
+ "java.lang.Object",
+ "java.util.Date")
+
+ private val classesToFind = classFilesToFind ++ List("TestSourceInRootPackage",
+ "scala.reflect.io.TestScalaSource",
+ "scala.reflect.io.TestJavaSource")
+
+ private val settings = new Settings
+
+ @Before
+ def initTempDirAndSourcePath: Unit = {
+ // In Java TemporaryFolder in JUnit is managed automatically using @Rule.
+ // It would work also in Scala after adding and extending a class like
+ // TestWithTempFolder.java containing it. But in this case it doesn't work when running tests
+ // from the command line - java class is not compiled due to some, misterious reasons.
+ // That's why such dirs are here created and deleted manually.
+ tempDir.create()
+ tempDir.newFile("TestSourceInRootPackage.scala")
+ val ioDir = tempDir.newFolder("scala", "reflect", "io")
+ new File(ioDir, "AbstractFile.scala").createNewFile()
+ new File(ioDir, "ZipArchive.java").createNewFile()
+ new File(ioDir, "TestScalaSource.scala").createNewFile()
+ new File(ioDir, "TestJavaSource.java").createNewFile()
+
+ settings.usejavacp.value = true
+ settings.sourcepath.value = tempDir.getRoot.getAbsolutePath
+ }
+
+ @After
+ def deleteTempDir: Unit = tempDir.delete()
+
+ private def createFlatClassPath(settings: Settings) =
+ new FlatClassPathResolver(settings).result
+
+ @Test
+ def testEntriesFromListOperationAgainstSeparateMethods: Unit = {
+ val classPath = createFlatClassPath(settings)
+
+ def compareEntriesInPackage(inPackage: String): Unit = {
+ val packages = classPath.packages(inPackage)
+ val classes = classPath.classes(inPackage)
+ val sources = classPath.sources(inPackage)
+ val FlatClassPathEntries(packagesFromList, classesAndSourcesFromList) = classPath.list(inPackage)
+
+ val packageNames = packages.map(_.name).sorted
+ val packageNamesFromList = packagesFromList.map(_.name).sorted
+ assertEquals(s"Methods list and packages for package '$inPackage' should return the same packages",
+ packageNames, packageNamesFromList)
+
+ val classFileNames = classes.map(_.name).sorted
+ val classFileNamesFromList = classesAndSourcesFromList.filter(_.binary.isDefined).map(_.name).sorted
+ assertEquals(s"Methods list and classes for package '$inPackage' should return entries for the same class files",
+ classFileNames, classFileNamesFromList)
+
+ val sourceFileNames = sources.map(_.name).sorted
+ val sourceFileNamesFromList = classesAndSourcesFromList.filter(_.source.isDefined).map(_.name).sorted
+ assertEquals(s"Methods list and sources for package '$inPackage' should return entries for the same source files",
+ sourceFileNames, sourceFileNamesFromList)
+
+ val uniqueNamesOfClassAndSourceFiles = (classFileNames ++ sourceFileNames).toSet
+ assertEquals(s"Class and source entries with the same name obtained via list for package '$inPackage' should be merged into one containing both files",
+ uniqueNamesOfClassAndSourceFiles.size, classesAndSourcesFromList.length)
+ }
+
+ packagesToTest foreach compareEntriesInPackage
+ }
+
+ @Test
+ def testCreatedEntriesAgainstRecursiveClassPath: Unit = {
+ val flatClassPath = createFlatClassPath(settings)
+ val recursiveClassPath = new PathResolver(settings).result
+
+ def compareEntriesInPackage(inPackage: String): Unit = {
+
+ @tailrec
+ def traverseToPackage(packageNameParts: Seq[String], cp: ClassPath[AbstractFile]): ClassPath[AbstractFile] = {
+ packageNameParts match {
+ case Nil => cp
+ case h :: t =>
+ cp.packages.find(_.name == h) match {
+ case Some(nestedCp) => traverseToPackage(t, nestedCp)
+ case _ => throw new Exception(s"There's no package $inPackage in recursive classpath - error when searching for '$h'")
+ }
+ }
+ }
+
+ val packageNameParts = if (inPackage == FlatClassPath.RootPackage) Nil else inPackage.split('.').toList
+ val recursiveClassPathInPackage = traverseToPackage(packageNameParts, recursiveClassPath)
+
+ val flatCpPackages = flatClassPath.packages(inPackage).map(_.name)
+ val pkgPrefix = PackageNameUtils.packagePrefix(inPackage)
+ val recursiveCpPackages = recursiveClassPathInPackage.packages.map(pkgPrefix + _.name)
+ assertEquals(s"Packages in package '$inPackage' on flat cp should be the same as on the recursive cp",
+ recursiveCpPackages, flatCpPackages)
+
+ val flatCpSources = flatClassPath.sources(inPackage).map(_.name).sorted
+ val recursiveCpSources = recursiveClassPathInPackage.classes
+ .filter(_.source.nonEmpty)
+ .map(_.name).sorted
+ assertEquals(s"Source entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
+ recursiveCpSources, flatCpSources)
+
+ val flatCpClasses = flatClassPath.classes(inPackage).map(_.name).sorted
+ val recursiveCpClasses = recursiveClassPathInPackage.classes
+ .filter(_.binary.nonEmpty)
+ .map(_.name).sorted
+ assertEquals(s"Class entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
+ recursiveCpClasses, flatCpClasses)
+ }
+
+ packagesToTest foreach compareEntriesInPackage
+ }
+
+ @Test
+ def testFindClassFile: Unit = {
+ val classPath = createFlatClassPath(settings)
+ classFilesToFind foreach { className =>
+ assertTrue(s"File for $className should be found", classPath.findClassFile(className).isDefined)
+ }
+ }
+
+ @Test
+ def testFindClass: Unit = {
+ val classPath = createFlatClassPath(settings)
+ classesToFind foreach { className =>
+ assertTrue(s"File for $className should be found", classPath.findClass(className).isDefined)
+ }
+ }
+}
diff --git a/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala b/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala
new file mode 100644
index 0000000000..77a2da828e
--- /dev/null
+++ b/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala
@@ -0,0 +1,18 @@
+package scala.tools.nsc
+package settings
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import scala.tools.testing.AssertUtil.assertThrows
+
+@RunWith(classOf[JUnit4])
+class ScalaVersionTest {
+ // SI-8711
+ @Test def versionUnparse() {
+ val v = "2.11.3"
+
+ assertEquals(ScalaVersion(v).unparse, v)
+ }
+}
diff --git a/test/junit/scala/tools/nsc/settings/SettingsTest.scala b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
index eda0c27834..96f83c4c2f 100644
--- a/test/junit/scala/tools/nsc/settings/SettingsTest.scala
+++ b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
@@ -164,4 +164,20 @@ class SettingsTest {
assertThrows[IllegalArgumentException](check("-m:a,b,-ab")(_ => true), _ contains "'ab' cannot be negated")
assertThrows[IllegalArgumentException](check("-m:a,ac,-uber,uber")(_ => true), _ contains "'uber' cannot be negated")
}
+
+ @Test def xSourceTest(): Unit = {
+ def check(expected: String, args: String*): Unit = {
+ val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
+ val (_, residual) = s.processArguments(args.toList, processAll = true)
+ assert(residual.isEmpty)
+ assertTrue(s.source.value == ScalaVersion(expected))
+ }
+ check(expected = "2.11.0") // default
+ check(expected = "2.11.0", "-Xsource:2.11")
+ check(expected = "2.10", "-Xsource:2.10.0")
+ check(expected = "2.12", "-Xsource:2.12")
+ assertThrows[IllegalArgumentException](check(expected = "2.11", "-Xsource"), _ == "-Xsource requires an argument, the syntax is -Xsource:<version>")
+ assertThrows[IllegalArgumentException](check(expected = "2.11", "-Xsource", "2.11"), _ == "-Xsource requires an argument, the syntax is -Xsource:<version>")
+ assertThrows[IllegalArgumentException](check(expected = "2.11", "-Xsource:2.invalid"), _ contains "There was a problem parsing 2.invalid")
+ }
}
diff --git a/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala b/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala
index d424f12710..69931c9e24 100644
--- a/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala
+++ b/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala
@@ -64,4 +64,16 @@ class CannotHaveAttrsTest {
assertThrows[IllegalArgumentException] { t.setType(tpe) }
}
}
+
+ class Attach
+ @Test
+ def attachmentsAreIgnored = {
+ attrlessTrees.foreach { t =>
+ t.setAttachments(NoPosition.update(new Attach))
+ assert(t.attachments == NoPosition)
+ t.updateAttachment(new Attach)
+ assert(t.attachments == NoPosition)
+ t.removeAttachment[Attach] // no exception
+ }
+ }
}
diff --git a/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala b/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala
index 524d2e45e0..91f94e09b6 100644
--- a/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala
+++ b/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala
@@ -19,7 +19,7 @@ class StdNamesTest {
}
@Test
- def testNewTermNameNegativeLenght(): Unit = {
+ def testNewTermNameNegativeLength(): Unit = {
assertEquals(nme.EMPTY, newTermName("foo".toCharArray, 0, -1))
assertEquals(nme.EMPTY, newTermName("foo".toCharArray, 0, 0))
}
diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
index e4be42ac96..f0f20acf07 100644
--- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
+++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
@@ -3,6 +3,9 @@ package symtab
import scala.reflect.ClassTag
import scala.reflect.internal.{Phase, NoPhase, SomePhase}
+import scala.tools.nsc.classpath.FlatClassPath
+import scala.tools.nsc.settings.ClassPathRepresentationType
+import scala.tools.util.FlatClassPathResolver
import scala.tools.util.PathResolver
import util.ClassPath
import io.AbstractFile
@@ -26,13 +29,28 @@ class SymbolTableForUnitTesting extends SymbolTable {
class LazyTreeCopier extends super.LazyTreeCopier with TreeCopier
override def isCompilerUniverse: Boolean = true
- def classPath = new PathResolver(settings).result
+
+ def classPath = platform.classPath
+ def flatClassPath: FlatClassPath = platform.flatClassPath
object platform extends backend.Platform {
val symbolTable: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
lazy val loaders: SymbolTableForUnitTesting.this.loaders.type = SymbolTableForUnitTesting.this.loaders
+
def platformPhases: List[SubComponent] = Nil
- val classPath: ClassPath[AbstractFile] = new PathResolver(settings).result
+
+ lazy val classPath: ClassPath[AbstractFile] = {
+ assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive,
+ "It's not possible to use the recursive classpath representation, when it's not the chosen classpath scanning method")
+ new PathResolver(settings).result
+ }
+
+ private[nsc] lazy val flatClassPath: FlatClassPath = {
+ assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat,
+ "It's not possible to use the flat classpath representation, when it's not the chosen classpath scanning method")
+ new FlatClassPathResolver(settings).result
+ }
+
def isMaybeBoxed(sym: Symbol): Boolean = ???
def needCompile(bin: AbstractFile, src: AbstractFile): Boolean = ???
def externalEquals: Symbol = ???
@@ -50,7 +68,12 @@ class SymbolTableForUnitTesting extends SymbolTable {
class GlobalMirror extends Roots(NoSymbol) {
val universe: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
- def rootLoader: LazyType = new loaders.PackageLoader(classPath)
+
+ def rootLoader: LazyType = settings.YclasspathImpl.value match {
+ case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath)
+ case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(classPath)
+ }
+
override def toString = "compiler mirror"
}
@@ -60,7 +83,7 @@ class SymbolTableForUnitTesting extends SymbolTable {
rm.asInstanceOf[Mirror]
}
- def settings: Settings = {
+ lazy val settings: Settings = {
val s = new Settings
// initialize classpath using java classpath
s.usejavacp.value = true
diff --git a/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala b/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala
new file mode 100644
index 0000000000..1fff9c9a32
--- /dev/null
+++ b/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala
@@ -0,0 +1,555 @@
+package scala.tools.nsc.transform.patmat
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.collection.mutable
+import scala.tools.nsc.{Global, Settings}
+
+object TestSolver extends Logic with Solving {
+
+ val global: Global = new Global(new Settings())
+
+ // disable max recursion depth in order to get all solutions
+ global.settings.YpatmatExhaustdepth.tryToSet("off" :: Nil)
+
+ object TestSolver extends Solver {
+
+ class Const {
+ override def toString: String = "Const"
+ }
+
+ val NullConst = new Const
+ type Type = Int
+
+ case class TypeConst(i: Int) extends Const
+
+ object TypeConst extends TypeConstExtractor
+
+ case class ValueConst(i: Int) extends Const
+
+ object ValueConst extends ValueConstExtractor {
+ def apply(t: Tree): Const = ???
+ }
+
+ case class Tree(name: String)
+
+ class Var(val x: Tree) extends AbsVar {
+
+ override def equals(other: scala.Any): Boolean = other match {
+ case that: Var => this.x == that.x
+ case _ => false
+ }
+
+ override def hashCode(): Int = x.hashCode()
+
+ override def toString: String = {
+ s"Var($x)"
+ }
+
+ def domainSyms = None
+
+ def implications = Nil
+
+ def mayBeNull = false
+
+ def propForEqualsTo(c: Const): Prop = ???
+
+ def registerEquality(c: Const) = ()
+
+ def registerNull() = ()
+
+ def symForStaticTp = None
+ }
+
+ object Var extends VarExtractor {
+ def apply(x: Tree): Var = new Var(x)
+
+ def unapply(v: Var): Some[Tree] = Some(v.x)
+ }
+
+ def prepareNewAnalysis() = {}
+
+ def reportWarning(msg: String) = sys.error(msg)
+
+ /**
+ * The DPLL procedure only returns a minimal mapping from literal to value
+ * such that the CNF formula is satisfied.
+ * E.g. for:
+ * `(a \/ b)`
+ * The DPLL procedure will find either {a = true} or {b = true}
+ * as solution.
+ *
+ * The expansion step will amend both solutions with the unassigned variable
+ * i.e., {a = true} will be expanded to {a = true, b = true} and
+ * {a = true, b = false}.
+ */
+ def expandUnassigned(solution: Solution): List[Model] = {
+ import solution._
+
+ // the number of solutions is doubled for every unassigned variable
+ val expandedModels = 1 << unassigned.size
+ var current = mutable.ArrayBuffer[Model]()
+ var next = mutable.ArrayBuffer[Model]()
+ current.sizeHint(expandedModels)
+ next.sizeHint(expandedModels)
+
+ current += model
+
+ // we use double buffering:
+ // read from `current` and create a two models for each model in `next`
+ for {
+ s <- unassigned
+ } {
+ for {
+ model <- current
+ } {
+ def force(s: Sym, pol: Boolean) = model + (s -> pol)
+
+ next += force(s, pol = true)
+ next += force(s, pol = false)
+ }
+
+ val tmp = current
+ current = next
+ next = tmp
+
+ next.clear()
+ }
+
+ current.toList
+ }
+
+ /**
+ * Old CNF conversion code, used for reference:
+ * - convert formula into NNF
+ * (i.e., no negated terms, only negated variables)
+ * - use distributive laws to convert into CNF
+ */
+ def eqFreePropToSolvableViaDistribution(p: Prop) = {
+ val symbolMapping = new SymbolMapping(gatherSymbols(p))
+
+ type Formula = Array[TestSolver.Clause]
+
+ def formula(c: Clause*): Formula = c.toArray
+
+ def merge(a: Clause, b: Clause) = a ++ b
+
+ def negationNormalFormNot(p: Prop): Prop = p match {
+ case And(ps) => Or(ps map negationNormalFormNot)
+ case Or(ps) => And(ps map negationNormalFormNot)
+ case Not(p) => negationNormalForm(p)
+ case True => False
+ case False => True
+ case s: Sym => Not(s)
+ }
+
+ def negationNormalForm(p: Prop): Prop = p match {
+ case Or(ps) => Or(ps map negationNormalForm)
+ case And(ps) => And(ps map negationNormalForm)
+ case Not(negated) => negationNormalFormNot(negated)
+ case True
+ | False
+ | (_: Sym) => p
+ }
+
+ val TrueF: Formula = Array()
+ val FalseF = Array(clause())
+ def lit(sym: Sym) = Array(clause(symbolMapping.lit(sym)))
+ def negLit(sym: Sym) = Array(clause(-symbolMapping.lit(sym)))
+
+ def conjunctiveNormalForm(p: Prop): Formula = {
+ def distribute(a: Formula, b: Formula): Formula =
+ (a, b) match {
+ // true \/ _ = true
+ // _ \/ true = true
+ case (trueA, trueB) if trueA.size == 0 || trueB.size == 0 => TrueF
+ // lit \/ lit
+ case (a, b) if a.size == 1 && b.size == 1 => formula(merge(a(0), b(0)))
+ // (c1 /\ ... /\ cn) \/ d = ((c1 \/ d) /\ ... /\ (cn \/ d))
+ // d \/ (c1 /\ ... /\ cn) = ((d \/ c1) /\ ... /\ (d \/ cn))
+ case (cs, ds) =>
+ val (big, small) = if (cs.size > ds.size) (cs, ds) else (ds, cs)
+ big flatMap (c => distribute(formula(c), small))
+ }
+
+ p match {
+ case True => TrueF
+ case False => FalseF
+ case s: Sym => lit(s)
+ case Not(s: Sym) => negLit(s)
+ case And(ps) =>
+ ps.toArray flatMap conjunctiveNormalForm
+ case Or(ps) =>
+ ps map conjunctiveNormalForm reduceLeft { (a, b) =>
+ distribute(a, b)
+ }
+ }
+ }
+ val cnf = conjunctiveNormalForm(negationNormalForm(p))
+ Solvable(cnf, symbolMapping)
+ }
+
+ }
+
+}
+
+/**
+ * Testing CNF conversion via Tseitin vs NNF & expansion.
+ */
+@RunWith(classOf[JUnit4])
+class SolvingTest {
+
+ import scala.tools.nsc.transform.patmat.TestSolver.TestSolver._
+
+ implicit val Ord: Ordering[TestSolver.TestSolver.Model] = Ordering.by {
+ _.toSeq.sortBy(_.toString()).toIterable
+ }
+
+ private def sym(name: String) = Sym(Var(Tree(name)), NullConst)
+
+ @Test
+ def testSymCreation() {
+ val s1 = sym("hello")
+ val s2 = sym("hello")
+ assertEquals(s1, s2)
+ }
+
+ /**
+ * Simplest possible test: solve a formula and check the solution(s)
+ */
+ @Test
+ def testUnassigned() {
+ val pSym = sym("p")
+ val solvable = propToSolvable(Or(pSym, Not(pSym)))
+ val solutions = TestSolver.TestSolver.findAllModelsFor(solvable)
+ val expected = List(Solution(Map(), List(pSym)))
+ assertEquals(expected, solutions)
+ }
+
+ /**
+ * Unassigned variables must be expanded
+ * for stable results
+ */
+ @Test
+ def testNoUnassigned() {
+ val pSym = sym("p")
+ val qSym = sym("q")
+ val solvable = propToSolvable(Or(pSym, Not(qSym)))
+ val solutions = findAllModelsFor(solvable)
+ val expanded = solutions.flatMap(expandUnassigned).sorted
+ val expected = Seq(
+ Map(pSym -> false, qSym -> false),
+ Map(pSym -> true, qSym -> false),
+ Map(pSym -> true, qSym -> true)
+ ).sorted
+
+ assertEquals(expected, expanded)
+ }
+
+ @Test
+ def testTseitinVsExpansionFrom_t7020() {
+ val formulas = Seq(
+ And(And(And(Not(sym("V1=null")),
+ sym("V1=scala.collection.immutable.::[?]")), And(Not(sym("V1=null")),
+ And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), sym("V3=Nil")))),
+ And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")),
+ Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")),
+ Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))))), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))))),
+
+ And(And(And(Not(sym("V1=null")),
+ sym("V1=scala.collection.immutable.::[?]")), And(Not(sym("V1=null")),
+ And(sym("V2=7"), sym("V3=Nil")))),
+ And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")),
+ Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")),
+ Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))))), And(And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil")))))))),
+
+ And(And(Not(sym("V1=null")),
+ sym("V1=scala.collection.immutable.::[?]")), And(Not(sym("V1=null")),
+ And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), sym("V3=Nil")))),
+
+ And(And(Not(sym("V1=null")), sym("V1=scala.collection.immutable.::[?]")),
+ And(Not(sym("V1=null")), And(sym("V2=7"), sym("V3=Nil")))),
+
+ And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")),
+ Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")),
+ Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))))), And(And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))))),
+
+ And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")),
+ Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")),
+ Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))))), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil"))))))),
+
+ And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")),
+ Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")),
+ Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))))), And(sym("V1=Nil"), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil"))))))))),
+
+ And(And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))), And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil"))))),
+
+ And(And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil")))))),
+
+ And(And(Or(sym("V3=scala.collection.immutable.::[?]"), sym("V3=Nil")),
+ Or(sym("V1=scala.collection.immutable.::[?]"), sym("V1=Nil"))),
+ And(And(Or(Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))),
+ Or(False, Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))), And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil")))))),
+
+ And(Not(sym("V1=null")), And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))),
+ sym("V3=Nil"))),
+
+ And(Not(sym("V1=null")), And(sym("V2=7"), sym("V3=Nil"))),
+
+ And(Not(sym("V1=null")), sym("V1=scala.collection.immutable.::[?]")),
+
+ And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+
+ And(Not(sym("V2=5")), Not(sym("V2=6"))),
+
+ And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))),
+
+ And(Or(Not(sym("V1=scala.collection.immutable.::[?]")),
+ Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")),
+ Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))))),
+
+ And(Or(Not(sym("V3=Nil")), Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))),
+
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null"))))),
+
+ And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))), And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil")))),
+
+ And(Or(Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))),
+
+ And(Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil"))),
+
+ And(Or(Or(sym("V1=null"), Not(sym("V1=scala.collection.immutable.::[?]"))),
+ Or(sym("V1=null"), Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")),
+ Not(sym("V2=6")))), Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil"))))))),
+
+ And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))),
+
+ And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))),
+ And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")),
+ Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")),
+ Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null")))))))), And(sym("V1=Nil"), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))))))),
+
+ And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), sym("V3=Nil")),
+
+ And(Or(sym("V3=scala.collection.immutable.::[?]"), Or(sym("V3=Nil"),
+ sym("V3=null"))), And(Or(Not(sym("V3=Nil")), Not(sym("V3=null"))),
+ And(Or(Not(sym("V3=scala.collection.immutable.::[?]")),
+ Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+ Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"),
+ sym("V1=null"))))))),
+
+ And(Or(sym("V3=scala.collection.immutable.::[?]"),
+ sym("V3=Nil")), Or(sym("V1=scala.collection.immutable.::[?]"),
+ sym("V1=Nil"))),
+
+ And(sym("V1=Nil"), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))))),
+
+ And(sym("V2=7"), sym("V3=Nil")),
+
+ False,
+
+ Not(sym("V1=Nil")),
+
+ Or(And(Not(sym("V2=4")),
+ And(Not(sym("V2=5")), Not(sym("V2=6")))), Not(sym("V3=Nil"))),
+
+ Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))),
+
+ Or(False,
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil")))),
+
+ Or(False, Or(Not(sym("V2=1")), Not(sym("V3=Nil")))),
+
+ Or(Not(sym("V1=Nil")), Not(sym("V1=null"))),
+
+ Or(Not(sym("V3=scala.collection.immutable.::[?]")), Not(sym("V3=null"))),
+
+ Or(Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))),
+
+ Or(Or(False,
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False,
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))),
+
+ Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil"))))),
+
+ Or(Or(sym("V1=null"),
+ Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"),
+ Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))),
+
+ Or(sym("V1=null"), Not(sym("V1=scala.collection.immutable.::[?]"))),
+
+ Or(sym("V1=null"),
+ Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))),
+ Not(sym("V3=Nil")))),
+
+ Or(sym("V1=null"), Or(Not(sym("V2=1")), Not(sym("V3=Nil")))),
+
+ Or(sym("V1=scala.collection.immutable.::[?]"),
+ Or(sym("V1=Nil"), sym("V1=null"))),
+
+ Or(sym("V1=scala.collection.immutable.::[?]"), sym("V1=Nil")),
+
+ Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))),
+
+ sym("V3=scala.collection.immutable.::[?]")
+ )
+
+ formulas foreach {
+ f =>
+ // build CNF
+ val tseitinCnf = propToSolvable(f)
+ val expansionCnf = eqFreePropToSolvableViaDistribution(f)
+
+ // ALL-SAT
+ val tseitinSolutions = findAllModelsFor(tseitinCnf)
+ val expansionSolutins = findAllModelsFor(expansionCnf)
+
+ // expand unassigned variables
+ // (otherwise solutions can not be compared)
+ val tseitinNoUnassigned = tseitinSolutions.flatMap(expandUnassigned).sorted
+ val expansionNoUnassigned = expansionSolutins.flatMap(expandUnassigned).sorted
+ assertEquals(tseitinNoUnassigned, expansionNoUnassigned)
+ }
+ }
+}
+
+
diff --git a/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala b/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
new file mode 100644
index 0000000000..f2926e3e17
--- /dev/null
+++ b/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.util
+
+import scala.reflect.io.AbstractFile
+import scala.tools.nsc.Settings
+import scala.tools.nsc.settings.ClassPathRepresentationType
+import scala.tools.util.PathResolverFactory
+
+/**
+ * Simple application to compare efficiency of the recursive and the flat classpath representations
+ */
+object ClassPathImplComparator {
+
+ private class TestSettings extends Settings {
+ val checkClasses = PathSetting("-checkClasses", "Specify names of classes which should be found separated with ;", "")
+ val requiredIterations = IntSetting("-requiredIterations",
+ "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
+ val cpCreationRepetitions = IntSetting("-cpCreationRepetitions",
+ "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
+ val cpLookupRepetitions = IntSetting("-cpLookupRepetitions",
+ "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
+ }
+
+ private class DurationStats(name: String) {
+ private var sum = 0L
+ private var iterations = 0
+
+ def noteMeasuredTime(millis: Long): Unit = {
+ sum += millis
+ iterations += 1
+ }
+
+ def printResults(): Unit = {
+ val avg = if (iterations == 0) 0 else sum.toDouble / iterations
+ println(s"$name - total duration: $sum ms; iterations: $iterations; avg: $avg ms")
+ }
+ }
+
+ private lazy val defaultClassesToFind = List(
+ "scala.collection.immutable.List",
+ "scala.Option",
+ "scala.Int",
+ "scala.collection.immutable.Vector",
+ "scala.util.hashing.MurmurHash3"
+ )
+
+ private val oldCpCreationStats = new DurationStats("Old classpath - create")
+ private val oldCpSearchingStats = new DurationStats("Old classpath - search")
+
+ private val flatCpCreationStats = new DurationStats("Flat classpath - create")
+ private val flatCpSearchingStats = new DurationStats("Flat classpath - search")
+
+ def main(args: Array[String]): Unit = {
+
+ if (args contains "-help")
+ usage()
+ else {
+ val oldCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Recursive)
+ val flatCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Flat)
+
+ val classesToCheck = oldCpSettings.checkClasses.value
+ val classesToFind =
+ if (classesToCheck.isEmpty) defaultClassesToFind
+ else classesToCheck.split(";").toList
+
+ def doTest(classPath: => ClassFileLookup[AbstractFile], cpCreationStats: DurationStats, cpSearchingStats: DurationStats,
+ cpCreationRepetitions: Int, cpLookupRepetitions: Int)= {
+
+ def createClassPaths() = (1 to cpCreationRepetitions).map(_ => classPath).last
+ def testClassLookup(cp: ClassFileLookup[AbstractFile]): Boolean = (1 to cpCreationRepetitions).foldLeft(true) {
+ case (a, _) => a && checkExistenceOfClasses(classesToFind)(cp)
+ }
+
+ val cp = withMeasuredTime("Creating classpath", createClassPaths(), cpCreationStats)
+ val result = withMeasuredTime("Searching for specified classes", testClassLookup(cp), cpSearchingStats)
+ println(s"The end of the test case. All expected classes found = $result \n")
+ }
+
+ (1 to oldCpSettings.requiredIterations.value) foreach { iteration =>
+ if (oldCpSettings.requiredIterations.value > 1)
+ println(s"Iteration no $iteration")
+
+ println("Recursive (old) classpath representation:")
+ doTest(PathResolverFactory.create(oldCpSettings).result, oldCpCreationStats, oldCpSearchingStats,
+ oldCpSettings.cpCreationRepetitions.value, oldCpSettings.cpLookupRepetitions.value)
+
+ println("Flat classpath representation:")
+ doTest(PathResolverFactory.create(flatCpSettings).result, flatCpCreationStats, flatCpSearchingStats,
+ flatCpSettings.cpCreationRepetitions.value, flatCpSettings.cpLookupRepetitions.value)
+ }
+
+ if (oldCpSettings.requiredIterations.value > 1) {
+ println("\nOld classpath - summary")
+ oldCpCreationStats.printResults()
+ oldCpSearchingStats.printResults()
+
+ println("\nFlat classpath - summary")
+ flatCpCreationStats.printResults()
+ flatCpSearchingStats.printResults()
+ }
+ }
+ }
+
+ /**
+ * Prints usage information
+ */
+ private def usage(): Unit =
+ println("""Use classpath and sourcepath options like in the case of e.g. 'scala' command.
+ | There are also two additional options:
+ | -checkClasses <semicolon separated class names> Specify names of classes which should be found
+ | -requiredIterations <int value> Repeat tests specified count of times (to check e.g. impact of caches)
+ | Note: Option -YclasspathImpl will be set automatically for each case.
+ """.stripMargin.trim)
+
+ private def loadSettings(args: List[String], implType: String) = {
+ val settings = new TestSettings()
+ settings.processArguments(args, processAll = true)
+ settings.YclasspathImpl.value = implType
+ if (settings.classpath.isDefault)
+ settings.classpath.value = sys.props("java.class.path")
+ settings
+ }
+
+ private def withMeasuredTime[T](operationName: String, f: => T, durationStats: DurationStats): T = {
+ val startTime = System.currentTimeMillis()
+ val res = f
+ val elapsed = System.currentTimeMillis() - startTime
+ durationStats.noteMeasuredTime(elapsed)
+ println(s"$operationName - elapsed $elapsed ms")
+ res
+ }
+
+ private def checkExistenceOfClasses(classesToCheck: Seq[String])(classPath: ClassFileLookup[AbstractFile]): Boolean =
+ classesToCheck.foldLeft(true) {
+ case (res, classToCheck) =>
+ val found = classPath.findClass(classToCheck).isDefined
+ if (!found)
+ println(s"Class $classToCheck not found") // of course in this case the measured time will be affected by IO operation
+ found
+ }
+}
diff --git a/test/junit/scala/tools/testing/AssertUtil.scala b/test/junit/scala/tools/testing/AssertUtil.scala
index 9b4833d46b..83a637783f 100644
--- a/test/junit/scala/tools/testing/AssertUtil.scala
+++ b/test/junit/scala/tools/testing/AssertUtil.scala
@@ -1,6 +1,11 @@
package scala.tools
package testing
+import org.junit.Assert
+import Assert.fail
+import scala.runtime.ScalaRunTime.stringOf
+import scala.collection.{ GenIterable, IterableLike }
+
/** This module contains additional higher-level assert statements
* that are ultimately based on junit.Assert primitives.
*/
@@ -21,6 +26,19 @@ object AssertUtil {
throw e
else return
}
- throw new AssertionError("Expression did not throw!")
+ fail("Expression did not throw!")
}
+
+ /** JUnit-style assertion for `IterableLike.sameElements`.
+ */
+ def assertSameElements[A, B >: A](expected: IterableLike[A, _], actual: GenIterable[B], message: String = ""): Unit =
+ if (!(expected sameElements actual))
+ fail(
+ f"${ if (message.nonEmpty) s"$message " else "" }expected:<${ stringOf(expected) }> but was:<${ stringOf(actual) }>"
+ )
+
+ /** Convenient for testing iterators.
+ */
+ def assertSameElements[A, B >: A](expected: IterableLike[A, _], actual: Iterator[B]): Unit =
+ assertSameElements(expected, actual.toList, "")
}
diff --git a/test/junit/scala/util/t7265.scala b/test/junit/scala/util/SpecVersionTest.scala
index 71f085d21d..e3e7a978f2 100644
--- a/test/junit/scala/util/t7265.scala
+++ b/test/junit/scala/util/SpecVersionTest.scala
@@ -1,14 +1,11 @@
package scala.util
-package test
import org.junit.Assert._
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import scala.util.PropertiesTrait
-
/** The java version property uses the spec version
* and must work for all "major.minor" and fail otherwise.
*/
@@ -24,6 +21,7 @@ class SpecVersionTest {
override lazy val scalaProps = new java.util.Properties
}
+ // SI-7265
@Test
def comparesCorrectly(): Unit = {
assert(sut isJavaAtLeast "1.5")
diff --git a/test/junit/scala/util/matching/regextract-char.scala b/test/junit/scala/util/matching/CharRegexTest.scala
index 50fdcd9d46..50fdcd9d46 100644
--- a/test/junit/scala/util/matching/regextract-char.scala
+++ b/test/junit/scala/util/matching/CharRegexTest.scala