diff options
Diffstat (limited to 'tests')
36 files changed, 864 insertions, 7 deletions
diff --git a/tests/bench/transactional/Benchmark.scala b/tests/bench/transactional/Benchmark.scala new file mode 100644 index 000000000..8af7ebb83 --- /dev/null +++ b/tests/bench/transactional/Benchmark.scala @@ -0,0 +1,5 @@ +package transactional +abstract class Benchmark { + def run(): Int +} + diff --git a/tests/bench/transactional/ImplicitMega.scala b/tests/bench/transactional/ImplicitMega.scala new file mode 100644 index 000000000..80e9c4a43 --- /dev/null +++ b/tests/bench/transactional/ImplicitMega.scala @@ -0,0 +1,67 @@ +package transactional +object MegaBench extends Benchmark { + type Transactional[T] = implicit Transaction => T + + def transaction[T](op: Transactional[T]): T = { + implicit val trans: Transaction = new Transaction + val res = op + trans.commit() + res + } + + def thisTransaction: Transactional[Transaction] = implicitly[Transaction] + + abstract class Op { + def f(x: Int): Transactional[Int] + } + + class Op0 extends Op { + def f(x: Int): Transactional[Int] = { + thisTransaction.println("0th step") + x + } + } + + class Op1 extends Op { + def f(x: Int): Transactional[Int] = { + thisTransaction.println("first step") + x + 1 + } + } + + class Op2 extends Op { + def f(x: Int): Transactional[Int] = { + thisTransaction.println("second step") + x + 2 + } + } + + class Op3 extends Op { + def f(x: Int): Transactional[Int] = { + thisTransaction.println("third step") + x + 3 + } + } + + val op = Array[Op](new Op0, new Op1, new Op2, new Op3) + + def f(x: Int, n: Int): Transactional[Int] = { + thisTransaction.println("fourth step") + if (n > 0) f(op(n % 4).f(x), n - 1) + else { + if (x % 2 != 0) thisTransaction.abort() + x + } + } + + def run(): Int = { + transaction { + val res = f(7, 10) + assert(!thisTransaction.isAborted) + assert(res == 22) + res + } + } +} + +object ImplicitMega extends Runner("megamorphic", MegaBench, 22) diff --git a/tests/bench/transactional/ImplicitMono.scala b/tests/bench/transactional/ImplicitMono.scala new file mode 100644 index 000000000..10391f191 --- /dev/null +++ b/tests/bench/transactional/ImplicitMono.scala @@ -0,0 +1,45 @@ +package transactional +object MonoBench extends Benchmark { + type Transactional[T] = implicit Transaction => T + + def transaction[T](op: Transactional[T]): T = { + implicit val trans: Transaction = new Transaction + val res = op + trans.commit() + res + } + + def thisTransaction: Transactional[Transaction] = implicitly[Transaction] + + def f1(x: Int): Transactional[Int] = { + thisTransaction.println("first step") + f2(x + 1) + } + def f2(x: Int): Transactional[Int] = { + thisTransaction.println("second step") + f3(x * x) + } + def f3(x: Int): Transactional[Int] = { + thisTransaction.println("third step") + f4(x + 1, 7) + } + def f4(x: Int, n: Int): Transactional[Int] = { + thisTransaction.println("fourth step") + if (n > 0) f4(x + 1, n - 1) + else { + if (x % 2 != 0) thisTransaction.abort() + x + } + } + + def run(): Int = { + transaction { + val res = f1(7) + assert(!thisTransaction.isAborted) + assert(res == 72) + res + } + } +} + +object ImplicitMono extends Runner("monomorphic implicits", MonoBench, 72) diff --git a/tests/bench/transactional/ReaderMonadic.scala b/tests/bench/transactional/ReaderMonadic.scala new file mode 100644 index 000000000..ce69c35ad --- /dev/null +++ b/tests/bench/transactional/ReaderMonadic.scala @@ -0,0 +1,87 @@ +package transactional + +case class Reader[R,A](run: R => A) { + def map[B](f: A => B): Reader[R, B] = Reader(r => f(run(r))) + def flatMap[B](f: A => Reader[R, B]): Reader[R, B] = Reader(r => f(run(r)).run(r)) +} + +object Reader { + def ask[R]: Reader[R,R] = Reader(r => r) +} + +object ReaderBench extends Benchmark { + type Transactional[T] = Reader[Transaction, T] + + def transaction[T](op: Transactional[T]): T = { + implicit val trans: Transaction = new Transaction + val res = op.run(trans) + trans.commit() + res + } + + def thisTransaction: Transactional[Transaction] = Reader.ask + + abstract class Op { + def f(x: Int): Transactional[Int] + } + + class Op0 extends Op { + def f(x: Int): Transactional[Int] = + for (trans <- thisTransaction) + yield { trans.println("0th step"); x } + } + + class Op1 extends Op { + def f(x: Int): Transactional[Int] = + for (trans <- thisTransaction) + yield { trans.println("first step"); x + 1 } + } + + class Op2 extends Op { + def f(x: Int): Transactional[Int] = + for (trans <- thisTransaction) + yield { trans.println("second step"); x + 2 } + } + + class Op3 extends Op { + def f(x: Int): Transactional[Int] = + for (trans <- thisTransaction) + yield { trans.println("third step"); x + 3 } + } + + val op = Array[Op](new Op0, new Op1, new Op2, new Op3) + + def f(x: Int, n: Int): Transactional[Int] = { + def rest(trans: Transaction): Transactional[Int] = { + trans.println("fourth step") + if (n > 0) { + for { + y <- op(n % 4).f(x) + z <- f(y: Int, n - 1) + } + yield z + } + else { + if (x % 2 != 0) + for (trans <- thisTransaction) + yield { trans.abort(); () } + Reader(_ => x) + } + } + thisTransaction.flatMap(rest) + } + + def run(): Int = { + transaction { + for (res <- f(7, 10)) + yield { + for (trans <- thisTransaction) + yield { assert(!trans.isAborted); () } + assert(res == 22) + res + } + } + } +} + +object ReaderMonadic extends Runner("reader monadic", ReaderBench, 22) diff --git a/tests/bench/transactional/Runner.scala b/tests/bench/transactional/Runner.scala new file mode 100644 index 000000000..48da7ff12 --- /dev/null +++ b/tests/bench/transactional/Runner.scala @@ -0,0 +1,25 @@ +package transactional +import System.nanoTime + +class Runner(name: String, bench: Benchmark, expected: Int) { + + val numIters = 10000000 + val numTests = 5 + + def run(): Unit = { + val start = nanoTime + var cnt = 0 + var i = 0 + while (i < numIters) { + cnt += bench.run() + i += 1 + } + assert(cnt == expected * numIters) + val duration = nanoTime - start + println(s"$name in ${duration / 1000000}ms") + } + + def main(args: Array[String]) = + for (i <- 0 until numTests) + run() +} diff --git a/tests/bench/transactional/Transaction.scala b/tests/bench/transactional/Transaction.scala new file mode 100644 index 000000000..dbb28d452 --- /dev/null +++ b/tests/bench/transactional/Transaction.scala @@ -0,0 +1,21 @@ +package transactional +import collection.mutable.ListBuffer + +class Transaction { + private val log = new ListBuffer[String] + def println(s: String): Unit = log += s + + private var aborted = false + private var committed = false + + def abort(): Unit = { aborted = true } + def isAborted = aborted + + def commit(): Unit = + if (!aborted && !committed) { + //Console.println("******* log ********") + //log.foreach(Console.println) + committed = true + } +} + diff --git a/tests/bench/transactional/results.md b/tests/bench/transactional/results.md new file mode 100644 index 000000000..702617ebb --- /dev/null +++ b/tests/bench/transactional/results.md @@ -0,0 +1,77 @@ +# Benchmark results for implicit compilation scenarios + +### Setup + +Three alternatives: + + 1. No implicit shortcuts + 2. Implicit shortcuts only for possible targets of megamorphic dispatch + (`specializeMonoTargets` in [ShortcutImplicits.scala](../../../compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala) set to false) + 3. Implicit shortcuts for all methods returning implicit function types + (`specializeMonoTargets` set to true) + +Two benchmarks: + + - `ImplicitMono`: All calls are monomorphic. + Code in [ImplicitMono.scala](./ImplicitMono.scala). + - `ImplicitMega` : About half of the calls are (4-way) megamorphic, + the others are monomorphic. + Code in [ImplicitMega.scala](./ImplicitMega.scala). + +### Results + +| Scheme | ImplicitMono | ImplicitMega | +|---------------------|-------------:|-------------:| +| no shortcuts | 1354ms | 3260ms +| | 955ms | 2906ms +| | 908ms | 2899ms +| | 906ms | 2887ms +| | 886ms | 2872ms +| only mega shortcuts | | + | 1243ms | 2472ms +| | 926ms | 2146ms +| | 925ms | 2169ms +| | 902ms | 2136ms +| | 913ms | 2179ms +| all shortcuts | | +| | 1354ms | 1940ms +| | 1039ms | 1563ms +| | 1031ms | 1593ms +| | 1065ms | 1548ms +| | 1016ms | 1579ms + +### Interpretation + +In the fully monomorphic benchmark, specializing +only megamorphic targets has the same performance as +not specializing at all (not surprising, since there +are no megamorphic targets). Specializing everything +incurs about a 14% performance hit (maybe due to the extra +code generated; it's hard to pin down what it is). + +Note: We compute relative performance differences by comparing the +second-best test runs of each series with each other. + +In the megamorphic benchmark, it's the other way round. +Specializing only megamorphic call-sites leads to a performance +improvement of about 36% compared to no specialization. Specializing +everything leads to another 37% improvement (85% total compared +to no specialization). + +I think we need larger benchmarks to decide whether we should +specialize monomorphic call-targets or not. + +### Comparing with the Reader Monad + +Translating `ImplicitMega` to the reader monad (code in [ReaderMonadic.scala](./ReaderMonadic.scala)) gives the following runtimes: + +| Reader | +|---------| +| 11563ms | +| 11108ms | +| 11300ms | +| 11098ms | +| 11159ms | + +This translates to a 710% slowdown compared to implicit function types +with full specialization.
\ No newline at end of file diff --git a/tests/neg/i1642.scala b/tests/neg/i1642.scala new file mode 100644 index 000000000..2f7644698 --- /dev/null +++ b/tests/neg/i1642.scala @@ -0,0 +1 @@ +class Test2(val valueVal: Test2) extends AnyVal // error: value class cannot wrap itself diff --git a/tests/neg/i1670.scala b/tests/neg/i1670.scala new file mode 100644 index 000000000..69c47eda7 --- /dev/null +++ b/tests/neg/i1670.scala @@ -0,0 +1 @@ +class A(a:Int, b:Int) extends AnyVal // error: value class needs to have exactly one val parameter diff --git a/tests/neg/i1779.scala b/tests/neg/i1779.scala new file mode 100644 index 000000000..92100fa06 --- /dev/null +++ b/tests/neg/i1779.scala @@ -0,0 +1,13 @@ +object Test { + implicit class Foo(sc: StringContext) { + object q { + def apply(arg: Any*): Int = 3 + } + } + + def f = { + val _parent = 3 + q"val hello = $_parent" + q"class $_" // error // error + } +} diff --git a/tests/neg/i1802.scala b/tests/neg/i1802.scala new file mode 100644 index 000000000..56da672a8 --- /dev/null +++ b/tests/neg/i1802.scala @@ -0,0 +1,21 @@ +import scala.collection.immutable.List +import scala.reflect.{ ClassTag, classTag } +import scala.language.implicitConversions + +object Exception { + type Catcher[+T] = PartialFunction[Throwable, T] + + def mkCatcher[Ex <: Throwable: ClassTag, T](isDef: Ex => Boolean, f: Ex => T) = new Catcher[T] { + private def downcast(x: Throwable): Option[Ex] = + if (classTag[Ex].runtimeClass.isAssignableFrom(x.getClass)) Some(x.asInstanceOf[Ex]) + else None + + def isDefinedAt(x: Throwable) = downcast(x) exists isDef + def apply(x: Throwable): T = f(downcast(x).get) + } + + def mkThrowableCatcher[T](isDef: Throwable => Boolean, f: Throwable => T) = mkCatcher(isDef, f) + + implicit def throwableSubtypeToCatcher[Ex <: Throwable: ClassTag, T](pf: PartialFunction[Ex, T]) = // error: cyclic reference + mkCatcher(pf.isDefinedAt _, pf.apply _) +} diff --git a/tests/neg/i1806.scala b/tests/neg/i1806.scala new file mode 100644 index 000000000..7e5e132f2 --- /dev/null +++ b/tests/neg/i1806.scala @@ -0,0 +1,7 @@ +trait A { + class Inner + } +trait B extends A { + class Inner extends super.Inner // error +} + diff --git a/tests/neg/i705-inner-value-class2.scala b/tests/neg/i705-inner-value-class2.scala index a084da338..d59449b6b 100644 --- a/tests/neg/i705-inner-value-class2.scala +++ b/tests/neg/i705-inner-value-class2.scala @@ -1,5 +1,5 @@ class Foo { - class B(val a: Int) extends AnyVal + class B(val a: Int) extends AnyVal // error: value class may not be a member of another class` } object Test { diff --git a/tests/neg/implicitDefs.scala b/tests/neg/implicitDefs.scala index 1489344c8..3bfe60434 100644 --- a/tests/neg/implicitDefs.scala +++ b/tests/neg/implicitDefs.scala @@ -8,4 +8,11 @@ object implicitDefs { implicit val x = 2 // error: type of implicit definition needs to be given explicitly implicit def y(x: Int) = 3 // error: result type of implicit definition needs to be given explicitly implicit def z(a: x.type): String = "" // error: implicit conversion may not have a parameter of singleton type + + def foo(implicit x: String) = 1 + + def bar() = { + implicit val x = foo // error: cyclic reference + x + } } diff --git a/tests/neg/t3683-modified.scala b/tests/neg/t3683-modified.scala new file mode 100644 index 000000000..19b981e0a --- /dev/null +++ b/tests/neg/t3683-modified.scala @@ -0,0 +1,20 @@ +sealed trait Foo +sealed trait Bar extends Foo +sealed trait W[T >: Bar <: Foo] +case class X() extends W[Foo] +case class XX() extends W[Bar] +case class Y() extends W[Bar] +case class Z[T >: T <: Foo]( // error: cyclic reference + z1: W[T] +) extends W[T] + +object Main { + // should warn for not including XX() + def f1(w: W[Bar]): Int = { + w match { + // case XX() => 2 + case Y() => 1 + case Z(z) => f1(z) + } + } +} diff --git a/tests/pending/pos/i1535.scala b/tests/pending/pos/i1535.scala new file mode 100644 index 000000000..a574ca706 --- /dev/null +++ b/tests/pending/pos/i1535.scala @@ -0,0 +1,9 @@ +object Example { + case class C[H, T](h: H, t: T) + + type I = Int + + val p + : C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,C[I,I]]]]]]]]]]]]]]]]]]]]]]] + = C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,C(1,1))))))))))))))))))))))) +} diff --git a/tests/pending/pos/i1710.scala b/tests/pending/pos/i1710.scala new file mode 100644 index 000000000..703244ea9 --- /dev/null +++ b/tests/pending/pos/i1710.scala @@ -0,0 +1,11 @@ +object Hello extends App { + + val (a: Int, b: Int) = (4, 5) // works + val (z, k): (4, 5) = (4, 5) // works + + val cd: (4, 5) = (4, 5) + val c: 4 = cd._1 + val d: 5 = cd._2 + val (x: 4, y: 5) = (4, 5) // doesn't work + +} diff --git a/tests/pending/run/i1732.scala b/tests/pending/run/i1732.scala new file mode 100644 index 000000000..748c9c3e5 --- /dev/null +++ b/tests/pending/run/i1732.scala @@ -0,0 +1,8 @@ +object Test { + import scala.util.control.Breaks + def main(args: Array[String]): Unit = { + Breaks.breakable { + Breaks.break + } + } +} diff --git a/tests/pickling/extmethods.scala b/tests/pickling/extmethods.scala index 1cbc9f2ee..af1882f7a 100644 --- a/tests/pickling/extmethods.scala +++ b/tests/pickling/extmethods.scala @@ -3,6 +3,5 @@ package extMethods trait That1[A] class T[A, This <: That1[A]](val x: Int) extends AnyVal { self: This => - var next: This = _ final def loop(x: This, cnt: Int): Int = loop(x, cnt + 1) } diff --git a/tests/pos/Monoid.scala b/tests/pos/Monoid.scala new file mode 100644 index 000000000..f6004cdf3 --- /dev/null +++ b/tests/pos/Monoid.scala @@ -0,0 +1,61 @@ +package strawman.typeclasses + +trait SemiGroup[T] { + def append(x: T, y: T): T +} +object SemiGroup { + class Ops { + implicit class InfixAppend[T: SemiGroup](self: T) { + def |+| (other: T): T = implicitly[SemiGroup[T]].append(self, other) + } + } + object ops extends Ops +} + +trait Monoid[T] extends SemiGroup[T] { + val id: T +} +object Monoid { + object ops extends SemiGroup.Ops +} + +trait Ring[T] extends Monoid[T] { + val zero = id + val one: T + def product(x: T, y: T): T +} +object Ring { + class Ops extends SemiGroup.Ops { + implicit class InfixProduct[T: Ring](self: T) { + def |*| (other: T): T = implicitly[Ring[T]].product(self, other) + } + } + object ops extends Ops +} + + + +object Test { + implicit object StringMonoid extends Monoid[String] { + def append(x: String, y: String): String = x ++ y + val id = "" + } + + implicit object IntRing extends Ring[Int] { + def append(x: Int, y: Int) = x + y + val id = 0 + val one = 1 + def product(x: Int, y: Int) = x * y + } + + import Monoid.ops._ // works in dotty, fails in scalac + import Ring.ops._ + "abc" |+| "def" + "abc" |+| StringMonoid.id + StringMonoid.id |+| "abc" + + 1 |+| 2 + 3 |*| 3 + + +} diff --git a/tests/pos/Patterns.scala b/tests/pos/Patterns.scala index aa369a77b..fd0d7e97a 100644 --- a/tests/pos/Patterns.scala +++ b/tests/pos/Patterns.scala @@ -108,3 +108,31 @@ object NestedPattern { val xss: List[List[String]] = ??? val List(List(x)) = xss } + +// Tricky case (exercised by Scala parser combinators) where we use +// both get/isEmpty and product-based pattern matching in different +// matches on the same types. +object ProductAndGet { + + trait Result[+T] + case class Success[+T](in: String, x: T) extends Result[T] { + def isEmpty = false + def get: T = x + } + case class Failure[+T](in: String, msg: String) extends Result[T] { + def isEmpty = false + def get: String = msg + } + + val r: Result[Int] = ??? + + r match { + case Success(in, x) => x + case Failure(in, msg) => -1 + } + + r match { + case Success(x) => x + case Failure(msg) => -1 + } +} diff --git a/tests/pos/i1540.scala b/tests/pos/i1540.scala index 7aa24f459..0fdfea235 100644 --- a/tests/pos/i1540.scala +++ b/tests/pos/i1540.scala @@ -1,6 +1,6 @@ class Casey1(val a: Int) { - def isDefined: Boolean = true - def isDefined(x: Int): Boolean = ??? + def isEmpty: Boolean = false + def isEmpty(x: Int): Boolean = ??? def get: Int = a def get(x: Int): String = ??? } diff --git a/tests/pos/i1540b.scala b/tests/pos/i1540b.scala index 2b4c5408e..f4408b0c7 100644 --- a/tests/pos/i1540b.scala +++ b/tests/pos/i1540b.scala @@ -1,6 +1,6 @@ class Casey1[T](val a: T) { - def isDefined: Boolean = true - def isDefined(x: T): Boolean = ??? + def isEmpty: Boolean = false + def isEmpty(x: T): Boolean = ??? def get: T = a def get(x: T): String = ??? } diff --git a/tests/pos/i1642.scala b/tests/pos/i1642.scala new file mode 100644 index 000000000..2fe67cf18 --- /dev/null +++ b/tests/pos/i1642.scala @@ -0,0 +1,2 @@ +class Test1(val x: Int) extends AnyVal +class Test2(val y: Test1) extends AnyVal diff --git a/tests/pos/i1704.scala b/tests/pos/i1704.scala new file mode 100644 index 000000000..94bc03c4d --- /dev/null +++ b/tests/pos/i1704.scala @@ -0,0 +1,4 @@ +trait AnyRef { + val StringMatch = new AnyRef {} + trait Something { (AnyRef) match { case (StringMatch) => } } +} diff --git a/tests/pos/i1755.scala b/tests/pos/i1755.scala new file mode 100644 index 000000000..1361ebeec --- /dev/null +++ b/tests/pos/i1755.scala @@ -0,0 +1,21 @@ +class hierarOverload { + trait AB { + type TB + protected trait A { val entities: List[TB] } + protected trait B + } + object NAnB { + type TB = nB + type TA = nA + class nA { List[nB]() } + class nB {} + } + def foo = { val t = new NAnB.TB() } +} +class hierarOverload2 { + object NAnB { + type TB = nB + class nB + } + def foo = { val t = new NAnB.TB() } +} diff --git a/tests/pos/i1777.scala b/tests/pos/i1777.scala new file mode 100644 index 000000000..381ff9139 --- /dev/null +++ b/tests/pos/i1777.scala @@ -0,0 +1,9 @@ +object Main extends App { + import scala.collection.immutable._ + case class Foo(s: String) + { + implicit val orderingS: Ordering[String] = Ordering[String] // Crash + val tree = TreeMap.empty ++ (1 to 100).map { i => Foo(i.toString) -> i } + println(tree.getClass) + } +} diff --git a/tests/pos/i1790.scala b/tests/pos/i1790.scala new file mode 100644 index 000000000..7535255f9 --- /dev/null +++ b/tests/pos/i1790.scala @@ -0,0 +1,15 @@ +import scala.util.control.NonFatal + +class Try[+T] { + def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = + try this match { + case Success(v) => s(v) + case Failure(e) => f(e) + } catch { + case NonFatal(e) => Failure(e) + } +} +final case class Success[+T](value: T) extends Try[T] +final case class Failure[+T](exception: Throwable) extends Try[T] { + def get: T = throw exception +} diff --git a/tests/pos/i1797.scala b/tests/pos/i1797.scala new file mode 100644 index 000000000..1f10082b7 --- /dev/null +++ b/tests/pos/i1797.scala @@ -0,0 +1 @@ +case class Tuple1[T](_1: T) diff --git a/tests/pos/i1803.scala b/tests/pos/i1803.scala new file mode 100644 index 000000000..19bf21918 --- /dev/null +++ b/tests/pos/i1803.scala @@ -0,0 +1,7 @@ +class C[T] + +object Test { + def f(x: C[Int]) = ??? + + f(new C {}) +} diff --git a/tests/pos/implicits.scala b/tests/pos/implicits.scala index 1a3e0b4da..feb48771f 100644 --- a/tests/pos/implicits.scala +++ b/tests/pos/implicits.scala @@ -6,4 +6,9 @@ object Test { val x: X = Byte.MinValue + def foo() = { + implicit val x = "abc" + implicitly[String] + } + } diff --git a/tests/pos/pos_valueclasses/optmatch.scala b/tests/pos/pos_valueclasses/optmatch.scala index a7995a455..ff1a17906 100644 --- a/tests/pos/pos_valueclasses/optmatch.scala +++ b/tests/pos/pos_valueclasses/optmatch.scala @@ -7,7 +7,7 @@ package optmatch class NonZeroLong(val value: Long) extends AnyVal { def get: Long = value - def isDefined: Boolean = get != 0l + def isEmpty: Boolean = get == 0l } object NonZeroLong { def unapply(value: Long): NonZeroLong = new NonZeroLong(value) diff --git a/tests/repl/innerClasses.check b/tests/repl/innerClasses.check new file mode 100644 index 000000000..72dc6ae45 --- /dev/null +++ b/tests/repl/innerClasses.check @@ -0,0 +1,5 @@ +scala> class A { class Inner } +defined class A +scala> class B extends A { class Inner2 extends super.Inner } +defined class B +scala> :quit diff --git a/tests/run/i1779.check b/tests/run/i1779.check new file mode 100644 index 000000000..4ef6e900e --- /dev/null +++ b/tests/run/i1779.check @@ -0,0 +1 @@ + extends diff --git a/tests/run/i1779.scala b/tests/run/i1779.scala new file mode 100644 index 000000000..e81bc97b6 --- /dev/null +++ b/tests/run/i1779.scala @@ -0,0 +1,13 @@ +object Test { + implicit class Foo(sc: StringContext) { + object q { + def unapply(arg: Any): Option[(Any, Any)] = + Some((sc.parts(0), sc.parts(1))) + } + } + + def main(args: Array[String]): Unit = { + val q"class $_ extends $_parent" = new Object + println(_parent) + } +} diff --git a/tests/run/implicitFuns.scala b/tests/run/implicitFuns.scala new file mode 100644 index 000000000..496fba0d3 --- /dev/null +++ b/tests/run/implicitFuns.scala @@ -0,0 +1,261 @@ +object Test { + def main(args: Array[String]): Unit = { + + implicit val world: String = "world!" + + val i1 = (implicit (s: String) => s.length > 2) + val i2 = {implicit (s: String) => s.length > 2} + + assert(i1) + assert(i2) + + val x: implicit String => Boolean = { implicit (s: String) => s.length > 2 } + + val xx: implicit (String, Int) => Int = implicit (x: String, y: Int) => x.length + y + + val y: String => Boolean = x + + object nested { + implicit val empty: String = "" + assert(!x) + } + + val yy: (String, Int) => Any = xx + + val z1: implicit String => Boolean = implicitly[String].length >= 2 + assert(z1) + + type StringlyBool = implicit String => Boolean + + val z2: StringlyBool = implicitly[String].length >= 2 + assert(z2) + + type Stringly[T] = implicit String => T + + val z3: Stringly[Boolean] = implicitly[String].length >= 2 + assert(z3) + + type GenericImplicit[X] = implicit X => Boolean + + val z4: GenericImplicit[String] = implicitly[String].length >= 2 + assert(z4) + + val b = x("hello") + + val b1: Boolean = b + + val bi = x + + val bi1: Boolean = bi + + val c = xx("hh", 22) + + val c1: Int = c + + Contextual.main(args) + + def foo(s: String): Stringly[Int] = 42 + + (if ("".isEmpty) foo("") else foo("")).apply("") + } +} + +object Contextual { + + class Key[+V] + + class Context(bindings: Map[Key[Any], Any]) { + def binding[V](key: Key[V]): Option[V] = + bindings.get(key).asInstanceOf[Option[V]] + def withBinding[V](key: Key[V], value: V): Context = + new Context(bindings + ((key, value))) + } + + val rootContext = new Context(Map()) + + val Source = new Key[String] + val Options = new Key[List[String]] + + type Ctx[T] = implicit Context => T + + def ctx: Ctx[Context] = implicitly[Context] + + def compile(s: String): Ctx[Boolean] = + runOn(new java.io.File(s))(ctx.withBinding(Source, s)) >= 0 + + def runOn(f: java.io.File): Ctx[Int] = { + val options = List("-verbose", "-explaintypes") + process(f).apply(ctx.withBinding(Options, options)) + } + + def process(f: java.io.File): Ctx[Int] = + ctx.binding(Source).get.length - ctx.binding(Options).get.length + + def main(args: Array[String]) = { + implicit val context: Context = rootContext + assert(compile("abc")) + assert(compile("ab")) + assert(!compile("a")) + } +} + +import collection.mutable.ListBuffer + +class Transaction { + private val log = new ListBuffer[String] + def println(s: String): Unit = log += s + + private var aborted = false + private var committed = false + + def abort(): Unit = { aborted = true } + def isAborted = aborted + + def commit(): Unit = + if (!aborted && !committed) { + Console.println("******* log ********") + log.foreach(Console.println) + committed = true + } +} + +object TransactionalExplicit { + + def transaction[T](op: Transaction => T) = { + val trans: Transaction = new Transaction + op(trans) + trans.commit() + } + + def f1(x: Int)(implicit thisTransaction: Transaction): Int = { + thisTransaction.println(s"first step: $x") + f2(x + 1) + } + def f2(x: Int)(implicit thisTransaction: Transaction): Int = { + thisTransaction.println(s"second step: $x") + f3(x * x) + } + def f3(x: Int)(implicit thisTransaction: Transaction): Int = { + thisTransaction.println(s"third step: $x") + if (x % 2 != 0) thisTransaction.abort() + x + } + + def main(args: Array[String]) = { + transaction { + implicit thisTransaction => + val res = f1(args.length) + println(if (thisTransaction.isAborted) "aborted" else s"result: $res") + } + } +} + +object Transactional { + type Transactional[T] = implicit Transaction => T + + def transaction[T](op: Transactional[T]) = { + implicit val trans: Transaction = new Transaction + op + trans.commit() + } + + def thisTransaction: Transactional[Transaction] = implicitly[Transaction] + + def f1(x: Int): Transactional[Int] = { + thisTransaction.println(s"first step: $x") + f2(x + 1) + } + def f2(x: Int): Transactional[Int] = { + thisTransaction.println(s"second step: $x") + f3(x * x) + } + def f3(x: Int): Transactional[Int] = { + thisTransaction.println(s"third step: $x") + if (x % 2 != 0) thisTransaction.abort() + x + } + + def main(args: Array[String]) = { + transaction { + val res = f1(args.length) + println(if (thisTransaction.isAborted) "aborted" else s"result: $res") + } + } +} + +object TransactionalExpansion { + + def transaction[T](op: Transaction => T) = { + val trans: Transaction = new Transaction + op.apply(trans) + trans.commit() + } + + def thisTransaction = $t: Transaction => $t + + def f1(x: Int) = { $t: Transaction => + thisTransaction.apply($t).println(s"first step: $x") + f2(x + 1).apply($t) + } + def f2(x: Int) = { $t: Transaction => + thisTransaction.apply($t).println(s"second step: $x") + f3(x * x).apply($t) + } + def f3(x: Int) = { $t: Transaction => + thisTransaction.apply($t).println(s"third step: $x") + if (x % 2 != 0) thisTransaction.apply($t).abort() + x + } + + def main(args: Array[String]) = { + transaction { $t => + val res = f1(args.length).apply($t) + println(if (thisTransaction.apply($t).isAborted) "aborted" else s"result: $res") + } + } +} + +object TransactionalAbstracted { + type Transactional[T] = implicit Transaction => T + + trait TransOps { + def thisTransaction: Transactional[Transaction] + def f1(x: Int): Transactional[Int] + def f2(x: Int): Transactional[Int] + def f3(x: Int): Transactional[Int] + } + + object TransOpsObj extends TransOps { + + def thisTransaction: Transactional[Transaction] = implicitly[Transaction] + + def f1(x: Int): Transactional[Int] = { + thisTransaction.println(s"first step: $x") + f2(x + 1) + } + def f2(x: Int): Transactional[Int] = { + thisTransaction.println(s"second step: $x") + f3(x * x) + } + def f3(x: Int): Transactional[Int] = { + thisTransaction.println(s"third step: $x") + if (x % 2 != 0) thisTransaction.abort() + x + } + } + + val transOps: TransOps = TransOpsObj + + def transaction[T](op: Transactional[T]) = { + implicit val trans: Transaction = new Transaction + op + trans.commit() + } + + def main(args: Array[String]) = { + transaction { + val res = transOps.f1(args.length) + println(if (transOps.thisTransaction.isAborted) "aborted" else s"result: $res") + } + } +} |