diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2010-09-16 22:26:24 +0000 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2010-09-16 22:26:24 +0000 |
commit | e557acb9a7d672c0635c3eaf9fe385adc41e5c86 (patch) | |
tree | d13db6639464acc57f0e44b4b3ef6f3e607ad403 /test/files/pos | |
parent | ce223fe7abc47af712382a64404604e75f9f4d20 (diff) | |
download | scala-e557acb9a7d672c0635c3eaf9fe385adc41e5c86.tar.gz scala-e557acb9a7d672c0635c3eaf9fe385adc41e5c86.tar.bz2 scala-e557acb9a7d672c0635c3eaf9fe385adc41e5c86.zip |
part 2 of the dependent method refactoring: imp...
part 2 of the dependent method refactoring: improved interaction with
implicit search (needed for oopsla paper)
more to come in this area, see e.g. #3346 (stanford edsl stuff)
reopens #13, which wasn't fixed properly before imo, anyway (have a look at -Xprint:typer output before this commit: a type that's not expressible in surface syntax is inferred -- also removed duplicate test file)
closes #3731: co-evolve type alias type symbols when their rhs is
updated and they are referenced by type selections (see typemap)
review by odersky
Diffstat (limited to 'test/files/pos')
17 files changed, 331 insertions, 33 deletions
diff --git a/test/files/pos/bug0013.scala b/test/files/pos/bug0013.scala deleted file mode 100644 index 999a2ab61c..0000000000 --- a/test/files/pos/bug0013.scala +++ /dev/null @@ -1,31 +0,0 @@ -// covariant linked list -abstract class M { self => - - type T - final type selfType = M {type T <: self.T} - type actualSelfType >: self.type <: selfType - - def next: selfType - - // I don't understand why this doesn't compile, but that's a separate matter - // error: method all2 cannot be accessed in M.this.selfType - // because its instance type => Stream[M{type T <: M.this.selfType#T}] - // contains a malformed type: M.this.selfType#T - // def all2: Stream[M {type T <: self.T}] = Stream.cons(self: actualSelfType, next.all2) - - - // compiles successfully - // def all3: Stream[M {type T <: self.T}] = all3Impl(self: actualSelfType) - // private def all3Impl(first: M {type T <: self.T}): Stream[M {type T <: self.T}] = Stream.cons(first, all3Impl(first.next)) - - - - def all4: Stream[M {type T <: self.T}] = Unrelated.all4Impl[T](self: actualSelfType) -} - -object Unrelated { - def all4Impl[U](first: M {type T <: U}): Stream[M {type T <: U}] = Stream.cons(first, all4Impl(first.next)) - - // compiles successfully - // def all4Impl[U](first: M {type T <: U}): Stream[M {type T <: U}] = Stream.cons(first, all4Impl[U](first.next)) -}
\ No newline at end of file diff --git a/test/files/pos/bug1279a.scala b/test/files/pos/bug1279a.scala index 7568d3afcd..9212b583d4 100644 --- a/test/files/pos/bug1279a.scala +++ b/test/files/pos/bug1279a.scala @@ -1,3 +1,4 @@ +// see #13 // providing the type parameter in the recursive call to all4Impl // avoids the problem @@ -31,8 +32,9 @@ abstract class M object Unrelated { - def all4Impl[U](first: M {type T <: U}): Stream[M {type T <: U}] = Stream.cons(first, all4Impl(first.next)) + // TODO!!! fix this bug for real, it compiles successfully, but weird types are inferred + // def all4Impl[U](first: M {type T <: U}): Stream[M {type T <: U}] = Stream.cons(first, all4Impl(first.next)) // compiles successfully -// def all4Impl[U](first: M {type T <: U}): Stream[M {type T <: U}] = Stream.cons(first, all4Impl[U](first.next)) + def all4Impl[U](first: M {type T <: U}): Stream[M {type T <: U}] = Stream.cons(first, all4Impl[U](first.next)) } diff --git a/test/files/pos/depmet_implicit_chaining_zw.flags b/test/files/pos/depmet_implicit_chaining_zw.flags new file mode 100644 index 0000000000..1c26b24745 --- /dev/null +++ b/test/files/pos/depmet_implicit_chaining_zw.flags @@ -0,0 +1 @@ +-Ydependent-method-types
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_chaining_zw.scala b/test/files/pos/depmet_implicit_chaining_zw.scala new file mode 100644 index 0000000000..e3a145ab38 --- /dev/null +++ b/test/files/pos/depmet_implicit_chaining_zw.scala @@ -0,0 +1,28 @@ +trait Zero +trait Succ[N] + +trait ZipWith[N, S] { + type T + val x: T = error("") +} + +object ZipWith { + implicit def ZeroZipWith[S] = new ZipWith[Zero, S] { + type T = Stream[S] + } + + implicit def SuccZipWith[N, S, R](implicit zWith : ZipWith[N, R]) = new ZipWith[Succ[N], S => R] { + type T = Stream[S] => zWith.T // dependent types replace the associated types functionality + } + + // can't use implicitly[ZipWith[Succ[Succ[Zero]], Int => String => Boolean]], + // since that will chop of the {type T = ... } refinement in adapt (pt = ZipWith[Succ[Succ[Zero]], Int => String => Boolean]) + // this works + // def zipWith(implicit zw: ZipWith[Succ[Succ[Zero]], Int => String => Boolean]): zw.T = zw.x + // thus, I present ?: implicitly on steroids! + def ?[T <: AnyRef](implicit w: T): w.type = w + + type _2 = Succ[Succ[Zero]] + val zw = ?[ZipWith[_2, Int => String => Boolean]].x // : Stream[Int] => Stream[String] => Stream[Boolean] + // val zw = implicitly[ZipWith[Succ[Succ[Zero]], Int => String => Boolean]{type T = Stream[Int] => Stream[String] => Stream[Boolean]}].x +}
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_norm_ret.flags b/test/files/pos/depmet_implicit_norm_ret.flags new file mode 100644 index 0000000000..1c26b24745 --- /dev/null +++ b/test/files/pos/depmet_implicit_norm_ret.flags @@ -0,0 +1 @@ +-Ydependent-method-types
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_norm_ret.scala b/test/files/pos/depmet_implicit_norm_ret.scala new file mode 100644 index 0000000000..4cdb2931c6 --- /dev/null +++ b/test/files/pos/depmet_implicit_norm_ret.scala @@ -0,0 +1,29 @@ +object Test{ + def ?[S <: AnyRef](implicit w : S) : w.type = w + + // fallback, lower priority (overloading rules apply: pick alternative in subclass lowest in subtyping lattice) + class ZipWithDefault { + implicit def ZeroZipWith[S] = new ZipWith[S] { + type T = Stream[S] + } + } + + object ZipWith extends ZipWithDefault { + // def apply[S: ZipWith](s : S) = ?[ZipWith[S]].zipWith(s) // TODO: bug return type should be inferred + def apply[S](s : S)(implicit zw: ZipWith[S]): zw.T = zw.zipWith(s) + + implicit def SuccZipWith[S,R](implicit zWith : ZipWith[R]) = new ZipWith[S => R] { + type T = Stream[S] => zWith.T // dependent types replace the associated types functionality + } + } + + trait ZipWith[S] { + type T + def zipWith : S => T = error("") + } + + // bug: inferred return type = (Stream[A]) => java.lang.Object with Test.ZipWith[B]{type T = Stream[B]}#T + // this seems incompatible with vvvvvvvvvvvvvvvvvvvvvv -- #3731 + def map[A,B](f : A => B) /* : Stream[A] => Stream[B]*/ = ZipWith(f) + val tst: Stream[Int] = map{x: String => x.length}(Stream("a")) +}
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_session.flags b/test/files/pos/depmet_implicit_oopsla_session.flags new file mode 100644 index 0000000000..1c26b24745 --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_session.flags @@ -0,0 +1 @@ +-Ydependent-method-types
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_session.scala b/test/files/pos/depmet_implicit_oopsla_session.scala new file mode 100644 index 0000000000..21588a56ad --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_session.scala @@ -0,0 +1,63 @@ +object Sessions { + trait Session[This] { + type Dual + type HasDual[D] = Session[This]{type Dual=D} + def run(p: This, dp: Dual): Unit + } + + implicit object StopSession extends Session[Stop] { + type Dual = Stop + + def run(p: Stop, dp: Stop): Unit = {} + } + + implicit def InDual[A, B](implicit sessionDIn: Session[B]) = + new Session[In[A, B]] { + type Dual = Out[A, sessionDIn.Dual] + + def run(p: In[A, B], dp: Dual): Unit = + sessionDIn.run(p.func(dp.x), dp.y) + } + + implicit def OutDual[A, B](implicit sessionDOut: Session[B]) = + new Session[Out[A, B]] { + type Dual = In[A, sessionDOut.Dual] + + def run(p: Out[A, B], dp: Dual): Unit = + sessionDOut.run(p.y, dp.func(p.x)) + } + + sealed case class Stop() + sealed case class In[-A, +B](func: A => B) + sealed case class Out[+A, +B](x: A, y: B) + + def addServer = + In{x: Int => + In{y: Int => System.out.println("Thinking") + Out(x+y, + Stop())}} + + def addClient = + Out(3, + Out(4, { System.out.println("Waiting") + In{z: Int => System.out.println(z) + Stop()}})) + + def runSession[S, D: Session[S]#HasDual](p: S, dp: D) = + implicitly[Session[S]#HasDual[D]].run(p, dp) + + // def runSession[S, D](p: S, dp: D)(implicit s: Session[S]#HasDual[D]) = + // s.run(p, dp) + // + // def runSession[S, D](p: S, dp: D)(implicit s: Session[S]{type Dual=D}) = + // s.run(p, dp) + + // TODO: can we relax the ordering restrictions on dependencies so that we can use + // def runSession[S](p: S, dp: s.Dual)(implicit s: Session[S]) = + // s.run(p, dp) + // to emphasise similarity of type parameters and implicit arguments: + // def runSession[S][val s: Session[S]](p: S, dp: s.Dual) = + // s.run(p, dp) + + def myRun = runSession(addServer, addClient) +}
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_session_2.flags b/test/files/pos/depmet_implicit_oopsla_session_2.flags new file mode 100644 index 0000000000..1c26b24745 --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_session_2.flags @@ -0,0 +1 @@ +-Ydependent-method-types
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_session_2.scala b/test/files/pos/depmet_implicit_oopsla_session_2.scala new file mode 100644 index 0000000000..5c3b78e3f5 --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_session_2.scala @@ -0,0 +1,87 @@ +object Sessions { + def ?[T <: AnyRef](implicit w: T): w.type = w + + // session states + sealed case class Stop() + sealed case class In[-Data, +Cont](recv: Data => Cont) + sealed case class Out[+Data, +Cont](data: Data, cont: Cont) + + // the type theory of communicating sessions: + + // an instance of type Session[S]{type Dual=D} is evidence that S and D are duals + // such a value witnesses this fact by describing how to compose an instance of S with an instance of D (through the run method) + trait Session[S] { type Self = S + type Dual + type HasDual[D] = Session[Self]{type Dual=D} + def run(self: Self, dual: Dual): Unit + } + + // friendly interface to the theory + def runSession[S, D: Session[S]#HasDual](session: S, dual: D) = + ?[Session[S]#HasDual[D]].run(session, dual) + + // facts in the theory: + + // ------------------------[StopDual] + // Stop is the dual of Stop + implicit object StopDual extends Session[Stop] { + type Dual = Stop + + def run(self: Self, dual: Dual): Unit = {} + } + + // CD is the dual of Cont + // -------------------------------------------[InDual] + // Out[Data, CD] is the dual of In[Data, Cont] + implicit def InDual[Data, Cont](implicit cont: Session[Cont]) = new Session[In[Data, Cont]] { + type Dual = Out[Data, cont.Dual] + + def run(self: Self, dual: Dual): Unit = + cont.run(self.recv(dual.data), dual.cont) + } + + // CD is the dual of Cont + // -------------------------------------------[OutDual] + // In[Data, CD] is the dual of Out[Data, Cont] + implicit def OutDual[Data, Cont](implicit cont: Session[Cont]) = new Session[Out[Data, Cont]] { + type Dual = In[Data, cont.Dual] + + def run(self: Self, dual: Dual): Unit = + cont.run(self.cont, dual.recv(self.data)) + } + + // a concrete session + def addServer = + In{x: Int => + In{y: Int => System.out.println("Thinking") + Out(x+y, + Stop())}} + + def addClient = + Out(3, + Out(4, { System.out.println("Waiting") + In{z: Int => System.out.println(z) + Stop()}})) + + def myRun = runSession(addServer, addClient) +} + +/* future improvements: + + + // def runSession[S, D](p: S, dp: D)(implicit s: Session[S]#HasDual[D]) = + // s.run(p, dp) + // + // def runSession[S, D](p: S, dp: D)(implicit s: Session[S]{type Dual=D}) = + // s.run(p, dp) + + // TODO: can we relax the ordering restrictions on dependencies so that we can write + // one possibility: graph of dependencies between arguments must be acyclic + // def runSession[S](p: S, dp: s.Dual)(implicit s: Session[S]) = + // s.run(p, dp) + // to emphasise similarity of type parameters and implicit arguments: + // def runSession[S][val s: Session[S]](p: S, dp: s.Dual) = + // s.run(p, dp) + + +*/
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_session_simpler.flags b/test/files/pos/depmet_implicit_oopsla_session_simpler.flags new file mode 100644 index 0000000000..1c26b24745 --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_session_simpler.flags @@ -0,0 +1 @@ +-Ydependent-method-types
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_session_simpler.scala b/test/files/pos/depmet_implicit_oopsla_session_simpler.scala new file mode 100644 index 0000000000..37bc0958d3 --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_session_simpler.scala @@ -0,0 +1,44 @@ +object Sessions { + trait Session { + type Dual <: Session + + def run(dp: Dual): Unit + } + + sealed case class Stop extends Session { + type Dual = Stop + + def run(dp: Dual): Unit = {} + } + + // can't write B <: Session{type Dual = BDual} due to limitations in type inference algorithm + // (type variables cannot occur on both sides of <:) + // using B#Dual instead of BDual is too imprecise, since it is disconnected from the actual argument that is passed for B + // would be nice if we could introduce a universal quantification over BDual that is not part of the + // type parameter list + sealed case class In[A, B <: Session, BDual <: Session](recv: A => B)(implicit dual: B <:< Session{type Dual=BDual}) extends Session { + type Dual = Out[A, BDual] + + def run(dp: Dual): Unit = recv(dp.data) run dp.cont + } + + sealed case class Out[A, B <: Session](data: A, cont: B) extends Session { + type Dual = In[A, cont.Dual, cont.Dual#Dual] + + def run(dp: Dual): Unit = cont run dp.recv(data) + } + + def addServer = + In{x: Int => + In{y: Int => System.out.println("Thinking") + Out(x+y, + Stop())}} + + def addClient = + Out(3, + Out(4, { System.out.println("Waiting") + In{z: Int => System.out.println(z) + Stop()}})) + + def myRun = addServer run addClient +} diff --git a/test/files/pos/depmet_implicit_oopsla_zipwith.flags b/test/files/pos/depmet_implicit_oopsla_zipwith.flags new file mode 100644 index 0000000000..1c26b24745 --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_zipwith.flags @@ -0,0 +1 @@ +-Ydependent-method-types
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_oopsla_zipwith.scala b/test/files/pos/depmet_implicit_oopsla_zipwith.scala new file mode 100644 index 0000000000..c76d02c1ae --- /dev/null +++ b/test/files/pos/depmet_implicit_oopsla_zipwith.scala @@ -0,0 +1,44 @@ +case class Zero() +case class Succ[N](x: N) +import Stream.{cons, continually} + +trait ZipWith[N, S] { + type T + + def manyApp: N => Stream[S] => T + def zipWith: N => S => T = n => f => manyApp(n)(continually(f)) +} +object ZipWith { + implicit def ZeroZipWith[S] = new ZipWith[Zero, S] { + type T = Stream[S] + + def manyApp = n => xs => xs + } + + implicit def SuccZipWith[N, S, R](implicit zw: ZipWith[N, R]) = + new ZipWith[Succ[N],S => R] { + type T = Stream[S] => zw.T + + def zapp[A, B](xs: Stream[A => B], ys: Stream[A]): Stream[B] = (xs, ys) match { + case (cons(f, fs), cons(s, ss)) => cons(f(s),zapp(fs, ss)) + case (_, _) => Stream.empty + } + + def manyApp = n => xs => ss => n match { + case Succ(i) => zw.manyApp(i)(zapp(xs, ss)) + } + } +} + +object Test { + def zWith[N, S](n: N, s: S)(implicit zw: ZipWith[N, S]): zw.T = zw.zipWith(n)(s) + + def zipWith0: Stream[Int] = zWith(Zero(),0) + +// (Stream[A]) => java.lang.Object with ZipWith[Zero,B]{type T = Stream[B]}#T +// should normalise to: Stream[A] => Stream[B] + def map[A, B](f: A => B) = zWith(Succ(Zero()),f) + + def zipWith3[A, B, C, D](f: A => B => C => D) = //: Stream[A] => Stream[B] => Stream[C] => Stream[D] = // BUG why do we need a return type? + zWith(Succ(Succ(Succ(Zero()))),f) +}
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_tpbetareduce.flags b/test/files/pos/depmet_implicit_tpbetareduce.flags new file mode 100644 index 0000000000..1c26b24745 --- /dev/null +++ b/test/files/pos/depmet_implicit_tpbetareduce.flags @@ -0,0 +1 @@ +-Ydependent-method-types
\ No newline at end of file diff --git a/test/files/pos/depmet_implicit_tpbetareduce.scala b/test/files/pos/depmet_implicit_tpbetareduce.scala new file mode 100644 index 0000000000..35d260683b --- /dev/null +++ b/test/files/pos/depmet_implicit_tpbetareduce.scala @@ -0,0 +1,12 @@ +trait HOSeq { + trait Accumulator[+coll[x], elT] + trait Iterable[+t] { + type m[+x] + def accumulator[t]: Accumulator[m, t] + } + implicit def listAccumulator[elT]: Accumulator[List, elT] = new Accumulator[List, elT] {} + trait List[+t] extends Iterable[t] { + type m[+x] = List[x] + def accumulator[t]: Accumulator[List, t] = listAccumulator[t] + } +}
\ No newline at end of file diff --git a/test/files/pos/t3731.scala b/test/files/pos/t3731.scala new file mode 100644 index 0000000000..9a617012b3 --- /dev/null +++ b/test/files/pos/t3731.scala @@ -0,0 +1,13 @@ +object Test{ + trait ZW[S]{type T} + def ZipWith[S, M <: ZW[S]]: M#T = error("ZW") + + // meh must be parameterised to force an asSeenFrom that + // duplicates the refinement in the TR's pre without updating its sym + def meh[A] = ZipWith[A, ZW[A]{type T=Stream[A]}] + + meh[Int]: Stream[Int] +} +// debugging output in coevolveSym should say: +// coevolved type T#11029 : Stream#3234[A#9228] to type T#11277 : Stream#3234[A#9227] +// with Test.ZW#9219[A#9228]{type T#11029 = Stream#3234[A#9228]} -> Test.ZW#9219[A#9227]{type T#11277 = Stream#3234[A#9227]} |