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:
parent
9f254e3fe3
commit
aaed85822c
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
class A[m[x] <: Option[x]]
|
||||
object a extends A[Some]
|
||||
object b extends A[List]
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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]
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
wellkinded_app.scala:3: error: x does not take type parameters
|
||||
type t = x[x]
|
||||
^
|
||||
one error found
|
|
@ -0,0 +1,4 @@
|
|||
// test well-kindedness checks
|
||||
class WellKinded[x] {
|
||||
type t = x[x]
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
wellkinded_app2.scala:3: error: s does not take type parameters
|
||||
val foo: s[Int]
|
||||
^
|
||||
one error found
|
|
@ -0,0 +1,4 @@
|
|||
// test well-kindedness checks
|
||||
class WellKinded[s <: Throwable] {
|
||||
val foo: s[Int]
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
// test well-kindedness checks -- syntax error
|
||||
class WellKindedWrongSyntax[s <: List] { // must be s[x] <: List[x]
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
// test well-kindedness checks -- arity error
|
||||
|
||||
class Monad[m[x]]
|
||||
|
||||
object mp extends Monad[Pair]
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
// test well-kindedness checks
|
||||
class Monad[m[x]]
|
||||
|
||||
object ms extends Monad[String]
|
|
@ -0,0 +1,4 @@
|
|||
object test {
|
||||
type z[a,b] = a => b
|
||||
def f : z[int,int] = (i => i + 1)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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]
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
trait SkolemisationOfHigherOrderBoundInMethod {
|
||||
def method[A, N[X <: A], M[X <: N[A]]]: unit
|
||||
}
|
|
@ -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]
|
||||
}
|
|
@ -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]
|
||||
}
|
|
@ -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"))
|
||||
}
|
|
@ -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]}
|
|
@ -0,0 +1,3 @@
|
|||
class Monad[m[x]]
|
||||
|
||||
object ml extends Monad[List]
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}*/
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
object test {
|
||||
def make[m[x], b]: m[b] = error("foo")
|
||||
val lst: List[Int] = make[List, Int]
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
trait test[b[_,_]] {
|
||||
def moo[a[_, _]] = error("a")
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
42
|
|
@ -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)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -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))
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Success(List(),Plus(1,2))
|
|
@ -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")))
|
||||
}
|
|
@ -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] = _
|
||||
}
|
Loading…
Reference in New Issue