Skip to content

Instantly share code, notes, and snippets.

@Blaisorblade
Last active December 21, 2015 05:49
Show Gist options
  • Save Blaisorblade/6259337 to your computer and use it in GitHub Desktop.
Save Blaisorblade/6259337 to your computer and use it in GitHub Desktop.
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!
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