adding test files from tcpoly branch without history -- much faster this way, sorry

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@10644 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
moors 2007-04-06 09:39:53 +00:00
parent 9f254e3fe3
commit aaed85822c
49 changed files with 933 additions and 0 deletions

View File

@ -0,0 +1,7 @@
higherkind_novalue.scala:2: error: type m takes type parameters
val x: m // type of kind *->* doesn't classify a value, but a val/def/... can only contain/return a value
^
higherkind_novalue.scala:3: error: type m takes type parameters
def y: m
^
two errors found

View File

@ -0,0 +1,4 @@
abstract class HigherKind[m[s]] {
val x: m // type of kind *->* doesn't classify a value, but a val/def/... can only contain/return a value
def y: m
}

View File

@ -0,0 +1,4 @@
tcpoly_bounds.scala:3: error: type arguments [scala.List] do not conform to class A's type parameter bounds [m<: [x]>: scala.Nothing <: scala.Option[x]]
object b extends A[List]
^
one error found

View File

@ -0,0 +1,3 @@
class A[m[x] <: Option[x]]
object a extends A[Some]
object b extends A[List]

View File

@ -0,0 +1,13 @@
tcpoly_typealias.scala:37: error: The kind of type m does not conform to the expected kind of type m<: [+x]>: scala.Nothing <: scala.Any in trait A.
BInv.this.m's type parameters do not match type m's expected parameters: type x (in trait BInv) is invariant, but type x (in trait A) is declared covariant
type m[x] = FooCov[x] // error: invariant x in alias def
^
tcpoly_typealias.scala:41: error: The kind of type m does not conform to the expected kind of type m<: [+x]>: scala.Nothing <: scala.Any in trait A.
BCon.this.m's type parameters do not match type m's expected parameters: type x (in trait BCon) is contravariant, but type x (in trait A) is declared covariant
type m[-x] = FooCon[x] // error: contravariant x
^
tcpoly_typealias.scala:45: error: The kind of type m does not conform to the expected kind of type m<: [+x]>: scala.Nothing <: scala.Any in trait A.
BBound.this.m's type parameters do not match type m's expected parameters: type x (in trait BBound)'s bounds >: scala.Nothing <: scala.Predef.String are stricter than type x (in trait A)'s declared bounds >: scala.Nothing <: scala.Any
type m[+x <: String] = FooBound[x] // error: x with stricter bound
^
three errors found

View File

@ -0,0 +1,47 @@
trait A {
type m[+x]
}
trait A2 {
type m[+x <: String]
}
trait A3 {
type m[x]
}
trait FooCov[+x]
trait FooCon[-x]
trait FooBound[+x <: String]
trait BOk1 extends A {
type m[+x] = FooCov[x]
}
trait BOk2 extends A2 {
type m[+x <: String] = FooBound[x]
}
trait BOk3 extends A2 {
type m[+x] = FooCov[x] // weaker bound
}
trait BOk4 extends A3 {
type m[+x] = FooCov[x] // weaker variance
}
// there are two aspects to check:
// does type alias signature (not considering RHS) correspond to abstract type member in super class
// does RHS correspond to the type alias sig
trait BInv extends A{
type m[x] = FooCov[x] // error: invariant x in alias def
}
trait BCon extends A{
type m[-x] = FooCon[x] // error: contravariant x
}
trait BBound extends A{
type m[+x <: String] = FooBound[x] // error: x with stricter bound
}

View File

@ -0,0 +1,5 @@
tcpoly_variance.scala:6: error: error overriding method str in class A of type => m[java.lang.Object];
method str has incompatible type => m[scala.Predef.String]
override def str: m[String] = error("foo") // since x in m[x] is invariant, ! m[String] <: m[Object]
^
one error found

View File

@ -0,0 +1,7 @@
class A[m[x]] {
def str: m[Object] = error("foo")
}
class B[m[x]] extends A[m] {
override def str: m[String] = error("foo") // since x in m[x] is invariant, ! m[String] <: m[Object]
}

View File

@ -0,0 +1,45 @@
tcpoly_variance_enforce.scala:15: error: the kinds of the type arguments (FooInvar) do not conform to the expected kinds of the type parameters (type m) in trait coll.
FooInvar's type parameters do not match type m's expected parameters: type x (in class FooInvar) is invariant, but type x is declared covariant
object fcollinv extends coll[FooInvar] // error
^
tcpoly_variance_enforce.scala:16: error: the kinds of the type arguments (FooContra) do not conform to the expected kinds of the type parameters (type m) in trait coll.
FooContra's type parameters do not match type m's expected parameters: type x (in class FooContra) is contravariant, but type x is declared covariant
object fcollcon extends coll[FooContra] // error
^
tcpoly_variance_enforce.scala:17: error: the kinds of the type arguments (FooString) do not conform to the expected kinds of the type parameters (type m) in trait coll.
FooString's type parameters do not match type m's expected parameters: type x (in class FooString)'s bounds >: scala.Nothing <: scala.Predef.String are stricter than type x's declared bounds >: scala.Nothing <: scala.Any
object fcollwb extends coll[FooString] // error
^
tcpoly_variance_enforce.scala:19: error: the kinds of the type arguments (FooCov) do not conform to the expected kinds of the type parameters (type m) in trait coll2.
FooCov's type parameters do not match type m's expected parameters: type x (in class FooCov) is covariant, but type x is declared contravariant
object fcoll2ok extends coll2[FooCov] // error
^
tcpoly_variance_enforce.scala:20: error: the kinds of the type arguments (FooInvar) do not conform to the expected kinds of the type parameters (type m) in trait coll2.
FooInvar's type parameters do not match type m's expected parameters: type x (in class FooInvar) is invariant, but type x is declared contravariant
object fcoll2inv extends coll2[FooInvar] // error
^
tcpoly_variance_enforce.scala:22: error: the kinds of the type arguments (FooString) do not conform to the expected kinds of the type parameters (type m) in trait coll2.
FooString's type parameters do not match type m's expected parameters: type x (in class FooString) is covariant, but type x is declared contravarianttype x (in class FooString)'s bounds >: scala.Nothing <: scala.Predef.String are stricter than type x's declared bounds >: scala.Nothing <: scala.Any
object fcoll2wb extends coll2[FooString] // error
^
tcpoly_variance_enforce.scala:27: error: the kinds of the type arguments (FooString) do not conform to the expected kinds of the type parameters (type m) in trait coll3.
FooString's type parameters do not match type m's expected parameters: type x (in class FooString)'s bounds >: scala.Nothing <: scala.Predef.String are stricter than type x's declared bounds >: scala.Nothing <: scala.Any
object fcoll3wb extends coll3[FooString] // error
^
tcpoly_variance_enforce.scala:30: error: the kinds of the type arguments (FooString,scala.Int) do not conform to the expected kinds of the type parameters (type m,type y) in trait coll4.
FooString's type parameters do not match type m's expected parameters: type x (in class FooString)'s bounds >: scala.Nothing <: scala.Predef.String are stricter than type x's declared bounds >: scala.Nothing <: y
object fcoll4_1 extends coll4[FooString, Int] // error
^
tcpoly_variance_enforce.scala:31: error: the kinds of the type arguments (FooString,scala.Any) do not conform to the expected kinds of the type parameters (type m,type y) in trait coll4.
FooString's type parameters do not match type m's expected parameters: type x (in class FooString)'s bounds >: scala.Nothing <: scala.Predef.String are stricter than type x's declared bounds >: scala.Nothing <: y
object fcoll4_2 extends coll4[FooString, Any] // error
^
tcpoly_variance_enforce.scala:37: error: the kinds of the type arguments (FooInvar) do not conform to the expected kinds of the type parameters (type m) in trait coll.
FooInvar's type parameters do not match type m's expected parameters: type x (in class FooInvar) is invariant, but type x is declared covariant
def x: coll[FooInvar] = error("foo") // error
^
tcpoly_variance_enforce.scala:38: error: the kinds of the type arguments (FooContra) do not conform to the expected kinds of the type parameters (type m) in trait coll.
FooContra's type parameters do not match type m's expected parameters: type x (in class FooContra) is contravariant, but type x is declared covariant
def y: coll[FooContra] = error("foo") // error
^
11 errors found

View File

@ -0,0 +1,42 @@
trait coll[m[+x]]
trait coll2[m[-x]]
trait coll3[m[x]]
trait coll4[m[x <: y], y]
class FooInvar[x]
class FooContra[-x]
class FooCov[+x]
class FooString[+x <: String]
object fcollok extends coll[FooCov]
object fcollinv extends coll[FooInvar] // error
object fcollcon extends coll[FooContra] // error
object fcollwb extends coll[FooString] // error
object fcoll2ok extends coll2[FooCov] // error
object fcoll2inv extends coll2[FooInvar] // error
object fcoll2con extends coll2[FooContra]
object fcoll2wb extends coll2[FooString] // error
object fcoll3ok extends coll3[FooCov]
object fcoll3inv extends coll3[FooInvar]
object fcoll3con extends coll3[FooContra]
object fcoll3wb extends coll3[FooString] // error
object fcoll4ok extends coll4[FooString, String]
object fcoll4_1 extends coll4[FooString, Int] // error
object fcoll4_2 extends coll4[FooString, Any] // error
object test {
var ok: coll[FooCov] = _
def x: coll[FooInvar] = error("foo") // error
def y: coll[FooContra] = error("foo") // error
}
// TODO: need test for rank N with N >: 2

View File

@ -0,0 +1,4 @@
wellkinded_app.scala:3: error: x does not take type parameters
type t = x[x]
^
one error found

View File

@ -0,0 +1,4 @@
// test well-kindedness checks
class WellKinded[x] {
type t = x[x]
}

View File

@ -0,0 +1,4 @@
wellkinded_app2.scala:3: error: s does not take type parameters
val foo: s[Int]
^
one error found

View File

@ -0,0 +1,4 @@
// test well-kindedness checks
class WellKinded[s <: Throwable] {
val foo: s[Int]
}

View File

@ -0,0 +1,4 @@
wellkinded_bounds.scala:2: error: class List takes type parameters
class WellKindedWrongSyntax[s <: List] { // must be s[x] <: List[x]
^
one error found

View File

@ -0,0 +1,3 @@
// test well-kindedness checks -- syntax error
class WellKindedWrongSyntax[s <: List] { // must be s[x] <: List[x]
}

View File

@ -0,0 +1,4 @@
wellkinded_wrongarity.scala:5: error: type Pair takes two type parameters, expected: one
object mp extends Monad[Pair]
^
one error found

View File

@ -0,0 +1,5 @@
// test well-kindedness checks -- arity error
class Monad[m[x]]
object mp extends Monad[Pair]

View File

@ -0,0 +1,4 @@
wellkinded_wrongarity2.scala:4: error: type String takes no type parameters, expected: one
object ms extends Monad[String]
^
one error found

View File

@ -0,0 +1,4 @@
// test well-kindedness checks
class Monad[m[x]]
object ms extends Monad[String]

View File

@ -0,0 +1,4 @@
object test {
type z[a,b] = a => b
def f : z[int,int] = (i => i + 1)
}

View File

@ -0,0 +1,20 @@
abstract class NullaryTest[T, m[s]] {
def nullary: String = "a"
val x = nullary
def nullary2: T
val x2 = nullary2
def nullary3: m[T]
val x3 = nullary3
}
class Concrete extends NullaryTest[Int, List] {
def nullary2 = 1
def nullary3 = List(1,2,3)
}
object test {
(new Concrete).nullary2
(new Concrete).nullary3
}

View File

@ -0,0 +1,10 @@
// test polymorphic nullary method calls
class A {
// built-in
synchronized {}
val x: String = "a".asInstanceOf[String]
// user-defined:
def polyNullary[T]: List[T] = Nil
}

View File

@ -0,0 +1,8 @@
// tests transformation of return type in typedTypeApply (see also tcpoly_gm.scala)
class As {
class A {
def foo: A.this.type = bar.asInstanceOf[A.this.type]
def foo2: this.type = bar.asInstanceOf[this.type]
def bar: A = null
}
}

View File

@ -0,0 +1,19 @@
trait Monad[T <: Bound[T], MyType[x <: Bound[x]], Bound[_]] {
def map[S <: Bound[S]](f: T => S): MyType[S]
def flatMap[S <: RBound[S], RContainer[x <: RBound[x]], RBound[_],
Result[x <: RBound[x]] <: Monad[x, RContainer, RBound]]
(f: T => Result[S]): Result[S]
def filter(p: T => Boolean): MyType[T]
}
class Set[T <: Ordered[T]] extends Monad[T, Set, Ordered] {
def map[S <: Ordered[S]](f: T => S): Set[S] = error("TODO")
def flatMap[S <: RBound[S], RContainer[x <: RBound[x]], RBound[_],
Result[x <: RBound[x]] <: Monad[x, RContainer, RBound]]
(f: T => Result[S]): Result[S] = error("TODO")
def filter(p: T => Boolean): Set[T] = error("TODO")
}

View File

@ -0,0 +1,14 @@
class Foo[t[x]<: Pair[Int, x]]
//
class MyPair[z](a: Int, b: z) extends Pair[Int, z](a,b)
object foo extends Foo[MyPair]
trait Monad[m[x <: Bound[x]], Bound[x], a] // TODO: variances!
trait ListMonad[a] extends Monad[List, Any, a]
trait MyOrdered[a]
trait MySet[x <: MyOrdered[x]]
trait SetMonad[a <: MyOrdered[a]] extends Monad[MySet, MyOrdered, a]

View File

@ -0,0 +1,15 @@
trait Rep[a] {
def rep[m[x]]: m[a] // typedTypeApply must use asSeenFrom to adapt the return type
// since rep is called on x: Rep[t]
// a must become t
}
case class ShowBin[b](app: b => String)
object foo {
def showBin[t](x: Rep[t], y: t): String = {
val r: ShowBin[t] = x.rep[ShowBin]
r.app(y)
}
}

View File

@ -0,0 +1,3 @@
trait SkolemisationOfHigherOrderBoundInMethod {
def method[A, N[X <: A], M[X <: N[A]]]: unit
}

View File

@ -0,0 +1,5 @@
trait Foo {
def flatMap[RT <: RBound[RT], RBound[_], Result[x <: RBound[x]]]: Result[RT]
// bounds for RT& = >: scala.this.Nothing <: RBound&[RT&]
// bounds for x = >: scala.this.Nothing <: RBound&[x]
}

View File

@ -0,0 +1,6 @@
trait Iterable[m[+x], +t] {
def flatMap[resColl[+x] <: Iterable[resColl, x], s](f: t => resColl[s]): resColl[s]
def foo[a[x]] = "a"
val x = foo[List]
}

View File

@ -0,0 +1,25 @@
trait Monad[T <: Bound[T], MyType[x <: Bound[x]], Bound[_]] {
def flatMap[S <: RBound[S], RContainer[x <: RBound[x]], RBound[_],
Result[x <: RBound[x]] <: Monad[x, RContainer, RBound]]
(f: T => Result[S]): Result[S]
def flatMap[S <: RBound[S], RContainer[x <: RBound[x]], RBound[_],
Result[x <: RBound[x]] <: Monad[x, RContainer, RBound]]
(f: T => Result[S], foo: String): Result[S]
def flatMap[S <: Bound[S]]
(f: T => MyType[S], foo: Int): MyType[S]
}
trait Test {
def moo: MList[Int]
class MList[T](el: T) extends Monad[T, List, Any] {
def flatMap[S <: RBound[S], RContainer[x <: RBound[x]], RBound[_],
Result[x <: RBound[x]] <: Monad[x, RContainer, RBound]]
(f: T => Result[S]): Result[S] = error("foo")
def flatMap[S <: RBound[S], RContainer[x <: RBound[x]], RBound[_],
Result[x <: RBound[x]] <: Monad[x, RContainer, RBound]]
(f: T => Result[S], foo: String): Result[S] = error("foo")
def flatMap[S]
(f: T => List[S], foo: Int): List[S] = error("foo")
}
val l: MList[String] = moo.flatMap[String, List, Any, MList]((x: Int) => new MList("String"))
}

View File

@ -0,0 +1,8 @@
trait FOO[B, m[A <: B]]
trait FOO2[A <: B, B]
trait FOO3[m[A <: B], B]
class Test {
def foo[a[x]] = "a"
}
//trait Idiom[idi[x]] { def foo: idi[Int]}

View File

@ -0,0 +1,3 @@
class Monad[m[x]]
object ml extends Monad[List]

View File

@ -0,0 +1,13 @@
trait Generic[g[x]] {
def unit: g[Unit]
}
trait Rep[t] {
def rep[m[x]](implicit gen: Generic[m]): m[t]
}
// testing that the return type is also transformed when checking overriding
// + that substitution (of types&symbols) preserves isHigherKinded when replacing a higher-kinded type with another one
object foo extends Rep[Unit] {
def rep[g[x]](implicit gen: Generic[g]): g[Unit]= gen.unit
}

View File

@ -0,0 +1,175 @@
package examples.tcpoly.collection;
trait HOSeq {
// an internal interface that encapsulates the accumulation of elements (of type elT) to produce
// a structure of type coll[elT] -- different kinds of collections should provide different implicit
// values implementing this interface, in order to provide more performant ways of building that structure
trait Accumulator[+coll[x], elT] {
def += (el: elT): Unit
def result: coll[elT]
}
// Iterable abstracts over the type of its structure as well as its elements (see PolyP's Bifunctor)
// m[x] is intentionally unbounded: fold can then be defined nicely
// variance: if we write m[+x] instead of +m[+x], x is an invariant position because its enclosing type
// is an invariant position -- should probably rule that out?
trait Iterable[+m[+x], +t] {
//def unit[a](orig: a): m[a]
def elements: Iterator[t]
// construct an empty accumulator that will produce the same structure as this iterable, with elements of type t
def accumulator[t]: Accumulator[m, t]
def filter(p: t => Boolean): m[t] = {
val buf = accumulator[t]
val elems = elements
while (elems.hasNext) { val x = elems.next; if (p(x)) buf += x }
buf.result
}
def map[s](f: t => s): m[s] = {
val buf = accumulator[s]
val elems = elements
while (elems.hasNext) buf += f(elems.next)
buf.result
}
// flatMap is a more specialized map, it only works if the mapped function produces Iterable values,
// which are then added to the result one by one
// the compiler should be able to find the right accumulator (implicit buf) to build the result
// to get concat, resColl = SingletonIterable, f = unit for SingletonIterable
def flatMap[resColl[+x] <: Iterable[resColl, x], s](f: t => resColl[s])(implicit buf: Accumulator[resColl, s]): resColl[s] = {
// TODO: would a viewbound for resColl[x] be better?
// -- 2nd-order type params are not yet in scope in view bound
val elems = elements
while (elems.hasNext) {
val elemss: Iterator[s] = f(elems.next).elements
while (elemss.hasNext) buf += elemss.next
}
buf.result
}
}
final class ListBuffer[A] {
private var start: List[A] = Nil
private var last: ::[A] = _
private var exported: boolean = false
/** Appends a single element to this buffer.
*
* @param x the element to append.
*/
def += (x: A): unit = {
if (exported) copy
if (start.isEmpty) {
last = new HOSeq.this.:: (x, Nil)
start = last
} else {
val last1 = last
last = new HOSeq.this.:: (x, null) // hack: ::'s tail will actually be last
//last1.tl = last
}
}
/** Converts this buffer to a list
*/
def toList: List[A] = {
exported = !start.isEmpty
start
}
/** Clears the buffer contents.
*/
def clear: unit = {
start = Nil
exported = false
}
/** Copy contents of this buffer */
private def copy = {
var cursor = start
val limit = last.tail
clear
while (cursor ne limit) {
this += cursor.head
cursor = cursor.tail
}
}
}
implicit def listAccumulator[elT]: Accumulator[List, elT] = new Accumulator[List, elT] {
private[this] val buff = new ListBuffer[elT]
def += (el: elT): Unit = buff += el
def result: List[elT] = buff.toList
}
trait List[+t] extends Iterable[List, t] {
def head: t
def tail: List[t]
def isEmpty: Boolean
def elements: Iterator[t] = new Iterator[t] {
var these = List.this
def hasNext: Boolean = !these.isEmpty
def next: t =
if (!hasNext)
throw new NoSuchElementException("next on empty Iterator")
else {
val result = these.head; these = these.tail; result
}
}
// construct an empty accumulator that will produce the same structure as this iterable, with elements of type t
def accumulator[t]: Accumulator[List, t] = listAccumulator[t]
}
// TODO: the var tl approach does not seem to work because subtyping isn't fully working yet
final case class ::[+b](hd: b, private val tl: List[b]) extends List[b] {
def head = hd
def tail = if(tl==null) this else tl // hack
override def isEmpty: boolean = false
}
case object Nil extends List[Nothing] {
def isEmpty = true
def head: Nothing =
throw new NoSuchElementException("head of empty list")
def tail: List[Nothing] =
throw new NoSuchElementException("tail of empty list")
}
}
// misc signatures collected from mailing list / library code:
/*override def flatMap[B](f: A => Iterable[B]): Set[B]
final override def flatMap[b](f: Any => Iterable[b]): Array[b]
def flatMap[b](f: a => Parser[b]) = new Parser[b]
override def flatMap[b](f: a => Iterable[b]): List[b]
MapResult[K] <: Seq[K]
FilterResult <: Seq[T]
Concat <: Seq[T]
Subseq <: Seq[T]
def map[K](f: T=>K): MapResult[K]
def filter(f: T=>Boolean): FilterResult
def subseq(from: int, to: int): Subseq
def flatMap[S <: Seq[K], K](f: T => S): S#Concat // legal?
def concat(others: Seq[T]): Concat
*/
/*trait Iterator[t] {
// @post hasAdvanced implies hasNext
// model def hasAdvanced: Boolean
def hasNext: Boolean // pure
// @pre hasAdvanced
def current: t // pure
// @pre hasNext
// @post hasAdvanced
def advance: Unit
}*/

View File

@ -0,0 +1,143 @@
package examples.tcpoly.collection;
trait HOSeq {
// an internal interface that encapsulates the accumulation of elements (of type elT) to produce
// a structure of type coll[elT] -- different kinds of collections should provide different implicit
// values implementing this interface, in order to provide more performant ways of building that structure
trait Accumulator[+coll[x], elT] {
def += (el: elT): Unit
def result: coll[elT]
}
// Iterable abstracts over the type of its structure as well as its elements (see PolyP's Bifunctor)
// m[x] is intentionally unbounded: fold can then be defined nicely
// variance: if we write m[+x] instead of +m[+x], x is an invariant position because its enclosing type
// is an invariant position -- should probably rule that out?
trait Iterable[+t] {
type m[+x]
//def unit[a](orig: a): m[a]
def elements: Iterator[t]
// construct an empty accumulator that will produce the same structure as this iterable, with elements of type t
def accumulator[t]: Accumulator[m, t]
def filter(p: t => Boolean): m[t] = {
val buf = accumulator[t]
val elems = elements
while (elems.hasNext) { val x = elems.next; if (p(x)) buf += x }
buf.result
}
def map[s](f: t => s): m[s] = {
val buf = accumulator[s]
val elems = elements
while (elems.hasNext) buf += f(elems.next)
buf.result
}
// flatMap is a more specialized map, it only works if the mapped function produces Iterable values,
// which are then added to the result one by one
// the compiler should be able to find the right accumulator (implicit buf) to build the result
// to get concat, resColl = SingletonIterable, f = unit for SingletonIterable
def flatMap[resColl[+x] <: Iterable[x], s](f: t => resColl[s])(implicit buf: Accumulator[resColl, s]): resColl[s] = {
// TODO: would a viewbound for resColl[x] be better?
// -- 2nd-order type params are not yet in scope in view bound
val elems = elements
while (elems.hasNext) {
val elemss: Iterator[s] = f(elems.next).elements
while (elemss.hasNext) buf += elemss.next
}
buf.result
}
}
final class ListBuffer[A] {
private var start: List[A] = Nil
private var last: ::[A] = _
private var exported: boolean = false
/** Appends a single element to this buffer.
*
* @param x the element to append.
*/
def += (x: A): unit = {
if (exported) copy
if (start.isEmpty) {
last = new HOSeq.this.:: (x, Nil)
start = last
} else {
val last1 = last
last = new HOSeq.this.:: (x, null) // hack: ::'s tail will actually be last
//last1.tl = last
}
}
/** Converts this buffer to a list
*/
def toList: List[A] = {
exported = !start.isEmpty
start
}
/** Clears the buffer contents.
*/
def clear: unit = {
start = Nil
exported = false
}
/** Copy contents of this buffer */
private def copy = {
var cursor = start
val limit = last.tail
clear
while (cursor ne limit) {
this += cursor.head
cursor = cursor.tail
}
}
}
implicit def listAccumulator[elT]: Accumulator[List, elT] = new Accumulator[List, elT] {
private[this] val buff = new ListBuffer[elT]
def += (el: elT): Unit = buff += el
def result: List[elT] = buff.toList
}
trait List[+t] extends Iterable[t] {
type m[+x] = List[x]
def head: t
def tail: List[t]
def isEmpty: Boolean
def elements: Iterator[t] = new Iterator[t] {
var these = List.this
def hasNext: Boolean = !these.isEmpty
def next: t =
if (!hasNext)
throw new NoSuchElementException("next on empty Iterator")
else {
val result = these.head; these = these.tail; result
}
}
// construct an empty accumulator that will produce the same structure as this iterable, with elements of type t
def accumulator[t]: Accumulator[List, t] = listAccumulator[t]
}
// TODO: the var tl approach does not seem to work because subtyping isn't fully working yet
final case class ::[+b](hd: b, private val tl: List[b]) extends List[b] {
def head = hd
def tail = if(tl==null) this else tl // hack
override def isEmpty: boolean = false
}
case object Nil extends List[Nothing] {
def isEmpty = true
def head: Nothing =
throw new NoSuchElementException("head of empty list")
def tail: List[Nothing] =
throw new NoSuchElementException("tail of empty list")
}
}

View File

@ -0,0 +1,4 @@
object test {
def make[m[x], b]: m[b] = error("foo")
val lst: List[Int] = make[List, Int]
}

View File

@ -0,0 +1,14 @@
// contributed by Lauri Alanko
trait TypeSub {
type l
type u
def castSub[f[+x]](fl : f[l]) : f[u]
def castSuper[f[-x]](fu : f[u]) : f[l] = {
type c[+y] = f[y] => f[l]
castSub[c]{ fl : f[l] => fl }(fu)
}
def castValue[t](lt : l with t) : u with t = {
type c[+y] = y with t
castSub[c](lt)
}
}

View File

@ -0,0 +1,7 @@
class A[m[+x]] {
def str: m[Object] = error("foo")
}
class B[m[+x]] extends A[m] {
override def str: m[String] = error("foo")
}

View File

@ -0,0 +1,3 @@
trait test[b[_,_]] {
def moo[a[_, _]] = error("a")
}

View File

@ -0,0 +1,15 @@
class MailBox {
//class Message
type Message = AnyRef
}
abstract class Actor {
private val in = new MailBox
def send(msg: in.Message) = error("foo")
def unstable: Actor = error("foo")
def dubiousSend(msg: MailBox#Message) =
unstable.send(msg) // in.Message becomes unstable.Message, but that's ok since Message is a concrete type member
}

View File

@ -0,0 +1,20 @@
package foo
trait Test[T] {
type Check[T] = Array[T] => Unit;
type MyPair[S] = Pair[T, S]
val pair1: Pair[T, Int]
val pair: MyPair[Int] = pair1
def check(xs: Array[T], c: Check[T]) = c(xs)
def check2[S](xs: Array[S], c: Check[S]) = c(xs)
}
object main extends Test[Int] {
val pair1 = (1,1)
implicit def topair(x: Int): Pair[Int, Int] = (x,x)
val pair2: MyPair[Int] = 1
val x: short = 1
}

View File

@ -0,0 +1 @@
42

View File

@ -0,0 +1,42 @@
trait Monads {
/**
* class Monad m where
* (>>=) :: m a -> (a -> m b) -> m b
* return :: a -> m a
*
* MonadTC encodes the above Haskell type class,
* an instance of MonadTC corresponds to a method dictionary.
* (see http://lampwww.epfl.ch/~odersky/talks/wg2.8-boston06.pdf)
*
* Note that the identity (`this') of the method dictionary does not really correspond
* to the instance of m[x] (`self') that is `wrapped': e.g., unit does not use `self' (which
* corresponds to the argument of the implicit conversion that encodes an instance of this type class)
*/
trait MonadTC[m[x], a] {
def unit[a](orig: a): m[a]
// >>='s first argument comes from the implicit definition constructing this "method dictionary"
def >>=[b](fun: a => m[b]): m[b]
}
}
/**
* instance Monad Maybe where
* (Just x) >>= k = k x
* Nothing >>= _ = Nothing
*/
trait OptionMonad extends Monads {
// this implicit method encodes the Monad type class instance for Option
implicit def OptionInstOfMonad[a](self: Option[a]): MonadTC[Option, a]
= new MonadTC[Option, a] {
def unit[a](orig: a) = Some(orig)
def >>=[b](fun: a => Option[b]): Option[b] = self match {
case Some(x) => fun(x)
case None => None
}
}
}
object Test extends OptionMonad with Application {
Console.println((Some("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") >>= (x => Some(x.length))).get)
}

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,16 @@
abstract class A[t[x]] {
def b: t[Int]
}
class B extends A[List] {
// underlying functionality being tested is overriding, but bugs manifest itself during erasure
// erasure should generate two methods: one that returns an Object (to implement the method in A)
// one that is as close as possible to the original method and thus returns a List
// the problem only manifests itself here -- but it's really a problem with overriding
// the link between this method and the method in A isn't seen
def b: List[Int] = List(1)
}
object Test extends Application {
Console.println((new B).b(0))
}

View File

@ -0,0 +1 @@
Success(List(),Plus(1,2))

View File

@ -0,0 +1,109 @@
trait Parsers {
type Input=List[char]
sealed class ParseResult[+t](val next: Input)
case class Success[+t](override val next: Input, result: t) extends ParseResult[t](next)
case class Failure(override val next: Input, msg: String) extends ParseResult[Nothing](next)
abstract class Parser[+t] {
def apply(in: Input): ParseResult[t]
}
// sequence
def sq[T, U](a: => Parser[T], b: => Parser[U]): Parser[Pair[T, U]] = new Parser[Pair[T, U]] {
def apply(in: Input): ParseResult[Pair[T, U]] = a(in) match {
case Success(next, x) => b(next) match {
case Success(next2, y) => Success(next2, Pair(x,y))
case Failure(_, msg) => Failure(in, msg)
}
case Failure(_, msg) => Failure(in, msg)
}
}
// ordered choice
def or[T, U <: T](a: => Parser[T], b: => Parser[U]): Parser[T] = new Parser[T] {
def apply(in: Input): ParseResult[T] = a(in) match {
case Success(next, x) => Success(next, x)
case Failure(_, _) => b(in) match {
case Success(next, y) => Success(next, y)
case Failure(_, msg) => Failure(in, msg)
}
}
}
// lifting
def lift[T, U](f: T => U)(a: => Parser[T]): Parser[U] = new Parser[U] {
def apply(in: Input): ParseResult[U] = a(in) match {
case Success(n, x) => Success(n, f(x))
case Failure(n, msg) => Failure(n, msg)
}
}
def accept[T](c: Char, r: T): Parser[T] = new Parser[T] {
def apply(in: Input) = in match {
case c2 :: n if c2 == c => Success(n, r)
case n => Failure(n, "expected "+c+" at the head of "+n)
}
}
def apply_++[s, tt](fun: Parser[s => tt], arg: Parser[s]): Parser[tt] = lift[Pair[s=>tt, s], tt]({case Pair(f, a) => f(a)})(sq(fun, arg))
def success[u](v: u): Parser[u] = new Parser[u] {
def apply(in: Input) = Success(in, v)
}
}
trait Idioms {
trait Idiom[idi[x]] {
def liftedApply[s, t](fun: idi[s => t])(arg: idi[s]): idi[t]
def pure[a](x: a): idi[a]
def pureMethod[a](name: String, x: a): idi[a] = pure(x) // hack for Mirrors: allow passing of method names
}
class IdiomaticTarget[idi[x], idiom <: Idiom[idi], s](i: idiom, tgt: s) {
def dot [t](fun: s => t, name: String) = new IdiomaticApp2[idi, idiom, t](i, i.liftedApply(i.pureMethod(name, fun))(i.pure(tgt)))
} // TODO: `.` --> java.lang.ClassFormatError: Illegal method name "." in class Idioms$IdiomaticTarget
class IdiomaticFunction[idi[x], idiom <: Idiom[idi], s, t](i: idiom, fun: s => t) {
def `(` (a: idi[s]) = new IdiomaticApp[idi, idiom, t](i, i.liftedApply(i.pure(fun))(a))
}
class IdiomaticApp[idi[x], idiom <: Idiom[idi], x](i: idiom, a: idi[x]) {
// where x <: s=>t -- TODO can this be expressed without generalised constraints?
def `,` [s, t](b: idi[s]) = new IdiomaticApp[idi, idiom, t](i, i.liftedApply(a.asInstanceOf[idi[s=>t]])(b))
def `)` : idi[x] = a
}
class IdiomaticApp2[idi[x], idiom <: Idiom[idi], x](i: idiom, a: idi[x]) extends IdiomaticApp[idi, idiom, x](i, a) {
def `(` [s, t](b: idi[s]) = `,`[s,t](b)
}
}
trait ParserIdioms extends Parsers with Idioms {
object ParserIdiom extends Idiom[Parser] {
def liftedApply[s, t](fun: Parser[s => t])(arg: Parser[s]): Parser[t] = apply_++(fun, arg)
def pure[a](x: a): Parser[a] = success(x)
}
implicit def parserIdiomFun[s, t](fun: s=>t): IdiomaticFunction[Parser, ParserIdiom.type, s, t] =
new IdiomaticFunction[Parser, ParserIdiom.type, s, t](ParserIdiom, fun)
implicit def parserIdiomTgt[s](tgt: s): IdiomaticTarget[Parser, ParserIdiom.type, s] =
new IdiomaticTarget[Parser, ParserIdiom.type, s](ParserIdiom, tgt)
trait Expr
case class Plus(a: Int, b: Int) extends Expr
def num = or(accept('0', 0), or(accept('1', 1),accept('2', 2)))
// TODO: how can parserIdiom(curry2(_)) be omitted?
def expr: Parser[Expr] = parserIdiomFun(curry2(Plus)) `(` num `,` num `)`
implicit def curry2[s,t,u](fun: (s, t)=>u)(a: s)(b: t) = fun(a, b)
implicit def curry3[r,s,t,u](fun: (r,s, t)=>u)(a: r)(b: s)(c: t) = fun(a, b, c)
}
object Test extends ParserIdioms with Application {
Console.println(expr(List.fromString("12")))
}

View File

@ -0,0 +1,12 @@
trait coll[+m[+x]]
class FooInvar[x]
class FooContra[-x]
class FooCov[+x]
object test {
var ok: coll[FooCov] = _
var x: coll[FooInvar] = _ // TODO: error should be reported only once instead of separately for getter and setter
var y: coll[FooContra] = _
}