From 42fd456acf5535a0ec980d207db8cc9e6abc6110 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Feb 2017 11:46:19 +0100 Subject: Re-instantiate depmeth tests These now compile with the changes to dependent methods, except for one which is invalid under dotty. --- tests/pos/depmet_implicit_norm_ret.scala | 34 ++++++++++ tests/pos/depmet_implicit_oopsla_session.scala | 63 +++++++++++++++++ tests/pos/depmet_implicit_oopsla_session_2.scala | 86 ++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 tests/pos/depmet_implicit_norm_ret.scala create mode 100644 tests/pos/depmet_implicit_oopsla_session.scala create mode 100644 tests/pos/depmet_implicit_oopsla_session_2.scala (limited to 'tests/pos') diff --git a/tests/pos/depmet_implicit_norm_ret.scala b/tests/pos/depmet_implicit_norm_ret.scala new file mode 100644 index 000000000..42bfb9fe1 --- /dev/null +++ b/tests/pos/depmet_implicit_norm_ret.scala @@ -0,0 +1,34 @@ +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]: Test.ZipWith[S]{type T = Stream[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]): Test.ZipWith[S => R]{type T = Stream[S] => zWith.T} = new ZipWith[S => R] { + type T = Stream[S] => zWith.T // dependent types replace the associated types functionality + } + } + + import ZipWith._ + + trait ZipWith[S] { + type T + def zipWith : S => T = sys.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 map1[A,B](f : A => B) = ZipWith(f)(SuccZipWith) // this typechecks but fails in -Ycheck:first + val tst1: Stream[Int] = map1[String, Int]{x: String => x.length}.apply(Stream("a")) + + def map2[A,B](f : A => B) = ZipWith(f) // this finds ZeroZipWith where scalac finds SuccZipWith and fails typechecking in the next line. + val tst2: Stream[Int] = map2{x: String => x.length}.apply(Stream("a")) +} diff --git a/tests/pos/depmet_implicit_oopsla_session.scala b/tests/pos/depmet_implicit_oopsla_session.scala new file mode 100644 index 000000000..a9c8e56ce --- /dev/null +++ b/tests/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]): Sessions.Session[Sessions.In[A,B]]{type Dual = Sessions.Out[A,sessionDIn.Dual]} = + 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]): Sessions.Session[Sessions.Out[A,B]]{type Dual = Sessions.In[A,sessionDOut.Dual]} = + 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) +} diff --git a/tests/pos/depmet_implicit_oopsla_session_2.scala b/tests/pos/depmet_implicit_oopsla_session_2.scala new file mode 100644 index 000000000..fcf18691a --- /dev/null +++ b/tests/pos/depmet_implicit_oopsla_session_2.scala @@ -0,0 +1,86 @@ +object Sessions { + + // 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) = + implicitly[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]): Sessions.Session[Sessions.In[Data,Cont]]{type Dual = Sessions.Out[Data,cont.Dual]} = 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]): Sessions.Session[Sessions.Out[Data,Cont]]{type Dual = Sessions.In[Data,cont.Dual]} = 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) + + +*/ -- cgit v1.2.3 From 0a839b80aaed89dfd0d84fa3308b72de590171cb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 1 Mar 2017 22:13:50 +0100 Subject: Move depmeth tests back to pending I believe this worked only accidentally because we matched more things with wildcards which turned out to be flawed. The test errors show some funky _#_ types, so not sure whether the tests are still valid or not. Moved back to pending awaiting further resolution. --- .../pos/depmet_implicit_oopsla_session.scala | 63 ++++++++++++++++ .../pos/depmet_implicit_oopsla_session_2.scala | 86 ++++++++++++++++++++++ tests/pos/depmet_implicit_oopsla_session.scala | 63 ---------------- tests/pos/depmet_implicit_oopsla_session_2.scala | 86 ---------------------- 4 files changed, 149 insertions(+), 149 deletions(-) create mode 100644 tests/pending/pos/depmet_implicit_oopsla_session.scala create mode 100644 tests/pending/pos/depmet_implicit_oopsla_session_2.scala delete mode 100644 tests/pos/depmet_implicit_oopsla_session.scala delete mode 100644 tests/pos/depmet_implicit_oopsla_session_2.scala (limited to 'tests/pos') diff --git a/tests/pending/pos/depmet_implicit_oopsla_session.scala b/tests/pending/pos/depmet_implicit_oopsla_session.scala new file mode 100644 index 000000000..a9c8e56ce --- /dev/null +++ b/tests/pending/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]): Sessions.Session[Sessions.In[A,B]]{type Dual = Sessions.Out[A,sessionDIn.Dual]} = + 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]): Sessions.Session[Sessions.Out[A,B]]{type Dual = Sessions.In[A,sessionDOut.Dual]} = + 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) +} diff --git a/tests/pending/pos/depmet_implicit_oopsla_session_2.scala b/tests/pending/pos/depmet_implicit_oopsla_session_2.scala new file mode 100644 index 000000000..fcf18691a --- /dev/null +++ b/tests/pending/pos/depmet_implicit_oopsla_session_2.scala @@ -0,0 +1,86 @@ +object Sessions { + + // 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) = + implicitly[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]): Sessions.Session[Sessions.In[Data,Cont]]{type Dual = Sessions.Out[Data,cont.Dual]} = 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]): Sessions.Session[Sessions.Out[Data,Cont]]{type Dual = Sessions.In[Data,cont.Dual]} = 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) + + +*/ diff --git a/tests/pos/depmet_implicit_oopsla_session.scala b/tests/pos/depmet_implicit_oopsla_session.scala deleted file mode 100644 index a9c8e56ce..000000000 --- a/tests/pos/depmet_implicit_oopsla_session.scala +++ /dev/null @@ -1,63 +0,0 @@ -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]): Sessions.Session[Sessions.In[A,B]]{type Dual = Sessions.Out[A,sessionDIn.Dual]} = - 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]): Sessions.Session[Sessions.Out[A,B]]{type Dual = Sessions.In[A,sessionDOut.Dual]} = - 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) -} diff --git a/tests/pos/depmet_implicit_oopsla_session_2.scala b/tests/pos/depmet_implicit_oopsla_session_2.scala deleted file mode 100644 index fcf18691a..000000000 --- a/tests/pos/depmet_implicit_oopsla_session_2.scala +++ /dev/null @@ -1,86 +0,0 @@ -object Sessions { - - // 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) = - implicitly[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]): Sessions.Session[Sessions.In[Data,Cont]]{type Dual = Sessions.Out[Data,cont.Dual]} = 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]): Sessions.Session[Sessions.Out[Data,Cont]]{type Dual = Sessions.In[Data,cont.Dual]} = 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) - - -*/ -- cgit v1.2.3 From 10d868ce335d1ecbb0a6acb8d4bd804d76edcac9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 2 Mar 2017 18:14:24 +0100 Subject: More tests and a typo fixed --- .../src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- tests/pos/t5070.scala | 23 ++++++++++++++++++++++ tests/pos/t5643.scala | 19 ++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/pos/t5643.scala (limited to 'tests/pos') diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 6042cc12c..168742257 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1312,7 +1312,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp1: RefinedType => tp2 match { case tp2: RefinedType if tp1.refinedName == tp2.refinedName => - // Given two refinements `T1 { X = S1 }` and `T2 { X = S2 }` rwrite to + // Given two refinements `T1 { X = S1 }` and `T2 { X = S2 }` rewrite to // `T1 & T2 { X B }` where `B` is the conjunction of the bounds of `X` in `T1` and `T2`. // // However, if `homogenizeArgs` is set, and both aliases `X = Si` are diff --git a/tests/pos/t5070.scala b/tests/pos/t5070.scala index 410afba14..0e5c0ffc0 100644 --- a/tests/pos/t5070.scala +++ b/tests/pos/t5070.scala @@ -13,3 +13,26 @@ class Test { implicitly[a.T](b(a)) // works } + + +class ImplicitVsTypeAliasTezt { + + class Monad[m[_]] { + type For[a] = _For[m, a] + implicit def toFor[a](m: m[a]): For[a] = throw new Error("todo") // lookup fails +// implicit def toFor[a](m: m[a]): _For[m, a] = throw new Error("todo") // fine. + } + + trait _For[m[_], a] { + def map[b](p: a => b): m[b] + } + + def useMonad[m[_], a](m: m[a])(implicit i: Monad[m]) = { + import i._ + + // value map is not a member of type parameter m[a] + for { + x <- m + } yield x.toString + } +} diff --git a/tests/pos/t5643.scala b/tests/pos/t5643.scala new file mode 100644 index 000000000..1ce34ba36 --- /dev/null +++ b/tests/pos/t5643.scala @@ -0,0 +1,19 @@ +object TupledEvidenceTest { + + abstract class TupledEvidence[M[_], T0] { type T = T0 } + + implicit def witnessTuple2[M[_], T1, T2](implicit ev1: M[T1], ev2: M[T2]): + TupledEvidence[M, (T1, T2)] { type T = (T1, T2) } = sys.error("") + + class GetResult[T] + + implicit val getString: GetResult[String] = new GetResult[String] + + implicit def getTuple[T](implicit w: TupledEvidence[GetResult, T]): GetResult[w.T] = sys.error("") + + def f[T : GetResult] = "" + + f[(String,String)](getTuple[(String, String)]) + + f[(String,String)] +} -- cgit v1.2.3