Skip to content

Instantly share code, notes, and snippets.

@mbloms
Last active September 17, 2020 17:02
Show Gist options
  • Save mbloms/4e453025d12114e445638b0b1c36431f to your computer and use it in GitHub Desktop.
Save mbloms/4e453025d12114e445638b0b1c36431f to your computer and use it in GitHub Desktop.
Improved version: Captured types are aggregated into a Union Type
import scala.spores._
object CapturedTest {
def main(args: Array[String]): Unit = {
val hejdu: String = "hejdu"
val s =
spore {
val str = hejdu;
val num = 2;
{() =>
println(str)
println(num)
}
}
s.apply()
}
}
//result of CapturedTest.scala after typer:
package <empty> {
import scala.spores._
final lazy module val CapturedTest: CapturedTest$ = new CapturedTest$()
final module class CapturedTest$() extends Object() {
this: CapturedTest.type =>
def main(args: Array[String]): Unit =
{
val hejdu: String = "hejdu"
val s: spores.NullarySpore[Unit]{Captured = String | Int} =
{
{
spores.typedSpore[Unit, String | Int](
{
{
{
val str: String = hejdu
val num: Int = 2
{
def $anonfun(): Unit =
{
println(str)
println(num)
}
closure($anonfun)
}
}
}
}
)
}
}
s.apply()
}
}
}
package scala.spores
import scala.quoted._
import scala.tasty.reflect._
transparent inline def spore[R](inline body: () => R) =
${sporeImpl('body)}
private def typedSpore[R,C](body: () => R) =
new NullarySpore[R] {
override type Captured = C
//override val captured = null
override def apply() = body()
override def skipScalaSamConversion: Nothing = ???
}
/** dummy function only for generating union types */
private def union(a: Any, b: Any): a.type | b.type = ???
private def sporeImpl[R: Type](expr: Expr[() => R])(using qctx: QuoteContext) = {
import qctx.tasty.{Block,ValDef,Statement}
/** Extract rhs term from val declaration */
transparent inline def rhs(statement: Statement) = statement match
case ValDef(str, tpt, Some(term)) => term.seal
case _ => report.throwError("Only val declarations are allowed in the spore header.")
/** Generate a bogus expression with the type of all captured variables
* NOTE: Currently the declared type in val defs are ignored, only the inferred type is used
*/
def capturedTypes(statements: List[Statement]): Expr[?] = statements match {
case List(statement) => rhs(statement) match
case '{$c: $ct} => c
case x::xs => rhs(x) match
case '{$c: $ct} => '{union($c,${capturedTypes(xs)})}
}
expr.unseal.underlyingArgument match
case block @ Block(statements,term) => capturedTypes(statements) match
case '{$c: $ct} =>
'{typedSpore[${summon[Type[R]]},$ct]($expr)}
case _ => ???
}
@mbloms
Copy link
Author

mbloms commented Sep 16, 2020

Output from running:

Look! I captured a scala.Predef.String
$anon.this.Captured
This is a block.
It looks like this:
Block(List(ValDef(str,TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),module Predef),type String)],Ident(hejdu))),Block(List(DefDef($anonfun,List(),List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Unit)],Apply(Ident(println),List(Ident(str))))),Closure(List(),Ident($anonfun),EmptyTree)))
hejdu
hejdu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment