Last active
December 21, 2015 05:49
-
-
Save Blaisorblade/6259337 to your computer and use it in GitHub Desktop.
Answer to Miles Sabin:
https://groups.google.com/d/msg/scala-internals/STmaXmH2RQg/DVNPf8i05FgJ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object api { class Universe { class Tree { type U = Universe.this.type; def toUTree(u: U): u.Tree = this } } } | |
def q(tree: api.Universe#Tree)(implicit u: tree.U): u.Tree = tree.toUTree(u) | |
def sameU(u: api.Universe)(t1: u.Tree, t2: u.Tree) = (t1, t2) | |
def sameU2(t1: api.Universe#Tree, t2: api.Universe#Tree)(implicit u: t1.U with t2.U): (u.Tree, u.Tree) = (t1.toUTree(u), t2.toUTree(u)) | |
val (u1, u2) = (new api.Universe, new api.Universe) | |
val (t1, t2) = (new u1.Tree, new u2.Tree) | |
implicit val iu1: u1.type = u1 | |
implicit val iu2: u2.type = u2 | |
//Test sameU2 | |
sameU2(t1, t2) //Fails | |
sameU2(t1, t1) | |
sameU2(t1, new u1.Tree) | |
sameU2(new u1.Tree, t1) | |
//This was transform: | |
def qBad[U <: api.Universe](tree: U#Tree): U#Tree = tree | |
q(t1) | |
q(t2) | |
//Call transform and q inline to help type inference: | |
sameU(u1)(t1, qBad(t1)) | |
sameU(u1)(t1, q(t1)) | |
sameU2(t1, qBad(t1)) | |
sameU2(t1, q(t1)) | |
//Call transform and q *not* inline, to avoid helping type inference too much: | |
val qBadT1 = qBad(t1) | |
val qBadT2 = qBad(t2) | |
val qT1 = q(t1) | |
sameU(u1)(t1, qBadT1) //Fails, although somewhat spuriously. | |
sameU(u1)(t1, qT1) //Succeeds! Yeah! | |
sameU2(t1, qBadT1) //Does not fail, even though qBadT1 was upcast. Is this good? | |
sameU2(t1, qT1) | |
sameU2(t1, qBadT2) //Does not fail either - doh! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
scala> object api { class Universe { class Tree { type U = Universe.this.type; def toUTree(u: U): u.Tree = this } } } | |
defined module api | |
scala> def q(tree: api.Universe#Tree)(implicit u: tree.U): u.Tree = tree.toUTree(u) | |
q: (tree: api.Universe#Tree)(implicit u: tree.U)u.Tree | |
scala> def sameU(u: api.Universe)(t1: u.Tree, t2: u.Tree) = (t1, t2) | |
sameU: (u: api.Universe)(t1: u.Tree, t2: u.Tree)(u.Tree, u.Tree) | |
scala> def sameU2(t1: api.Universe#Tree, t2: api.Universe#Tree)(implicit u: t1.U with t2.U): (u.Tree, u.Tree) = (t1.toUTree(u), t2.toUTree(u)) | |
sameU2: (t1: api.Universe#Tree, t2: api.Universe#Tree)(implicit u: t1.U with t2.U)(u.Tree, u.Tree) | |
scala> | |
scala> val (u1, u2) = (new api.Universe, new api.Universe) | |
u1: api.Universe = api$Universe@54405a01 | |
u2: api.Universe = api$Universe@4cd522dd | |
scala> val (t1, t2) = (new u1.Tree, new u2.Tree) | |
t1: u1.Tree = api$Universe$Tree@331d3edd | |
t2: u2.Tree = api$Universe$Tree@450a3962 | |
scala> implicit val iu1: u1.type = u1 | |
iu1: u1.type = api$Universe@54405a01 | |
scala> implicit val iu2: u2.type = u2 | |
iu2: u2.type = api$Universe@4cd522dd | |
scala> | |
scala> //Test sameU2 | |
scala> sameU2(t1, t2) //Fails | |
<console>:16: error: could not find implicit value for parameter u: t1.U with t2.U | |
sameU2(t1, t2) //Fails | |
^ | |
scala> sameU2(t1, t1) | |
res1: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> sameU2(t1, new u1.Tree) | |
res2: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@7b8d343a) | |
scala> sameU2(new u1.Tree, t1) | |
res3: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@42049d11,api$Universe$Tree@331d3edd) | |
scala> | |
scala> //This was transform: | |
scala> def qBad[U <: api.Universe](tree: U#Tree): U#Tree = tree | |
qBad: [U <: api.Universe](tree: U#Tree)U#Tree | |
scala> | |
scala> q(t1) | |
res4: iu1.Tree = api$Universe$Tree@331d3edd | |
scala> q(t2) | |
res5: iu2.Tree = api$Universe$Tree@450a3962 | |
scala> | |
scala> //Call transform and q inline to help type inference: | |
scala> sameU(u1)(t1, qBad(t1)) | |
res6: (u1.Tree, u1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> sameU(u1)(t1, q(t1)) | |
res7: (u1.Tree, u1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> | |
scala> sameU2(t1, qBad(t1)) | |
res8: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> sameU2(t1, q(t1)) | |
res9: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> | |
scala> //Call transform and q *not* inline, to avoid helping type inference too much: | |
scala> | |
scala> val qBadT1 = qBad(t1) | |
qBadT1: api.Universe#Tree = api$Universe$Tree@331d3edd | |
scala> val qBadT2 = qBad(t2) | |
qBadT2: api.Universe#Tree = api$Universe$Tree@450a3962 | |
scala> val qT1 = q(t1) | |
qT1: iu1.Tree = api$Universe$Tree@331d3edd | |
scala> | |
scala> sameU(u1)(t1, qBadT1) //Fails, although somewhat spuriously. | |
<console>:17: error: type mismatch; | |
found : api.Universe#Tree | |
required: u1.Tree | |
sameU(u1)(t1, qBadT1) //Fails, although somewhat spuriously. | |
^ | |
scala> sameU(u1)(t1, qT1) //Succeeds! Yeah! | |
res11: (u1.Tree, u1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> | |
scala> sameU2(t1, qBadT1) //Does not fail, even though qBadT1 was upcast. Is this good? | |
res12: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> sameU2(t1, qT1) | |
res13: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@331d3edd) | |
scala> | |
scala> sameU2(t1, qBadT2) //Does not fail either - doh! | |
res14: (iu1.Tree, iu1.Tree) = (api$Universe$Tree@331d3edd,api$Universe$Tree@450a3962) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment