Skip to content

Instantly share code, notes, and snippets.

@puffnfresh
Last active December 11, 2015 01:58
Show Gist options
  • Save puffnfresh/4526736 to your computer and use it in GitHub Desktop.
Save puffnfresh/4526736 to your computer and use it in GitHub Desktop.
Removing any2unit via a macro.
import language.experimental.{ macros => scalaMacros }
import reflect.macros.Context
package object macros {
def safe[A](expr: A) = macro safeImpl[A]
def safeImpl[A](c: Context)(expr: c.Expr[A]): c.Expr[A] = {
import c.universe._
def isIgnoredStatement(tree: Tree) = tree match {
// Scala creates synthetic blocks with <init> calls on classes.
// The calls return Object so we need to ignore them.
case Apply(Select(_, nme.CONSTRUCTOR), _) => true
case _ => false
}
object NoUnit extends Traverser {
override def traverse(tree: Tree) = {
tree match {
case Block(statements, _) =>
statements.foreach { stat =>
val unitLike = stat.tpe =:= typeOf[Unit] || stat.isDef || isIgnoredStatement(stat)
if (!unitLike)
c.error(stat.pos, "Statements must return Unit")
}
case _ =>
}
super.traverse(tree)
}
}
NoUnit.traverse(expr.tree)
expr
}
}
// No any2unit!
Macros.safe {
def x(a: Int) = {
// Won't compile:
// a
println("Returning a")
a
}
// Won't compile:
// 1
// x(1)
// x _
println("HELLO")
println("HELLO")
}
@retronym
Copy link

  • c.error(stat.pos, msg) is better form.
  • you could use a Traverser, rather than a Transformer, the easiest way is via:
tree.foreach {
  case Block(stats, _) => ...
  case _ => 
}
  • A bunch of standard names are in Universe#{nme, tpnme}
scala> reflect.runtime.universe.nme.CONSTRUCTOR
res1: reflect.runtime.universe.nme.NameType = <init>

scala> reflect.runtime.universe.tpnme.<TAB>
EMPTY           ERROR           NameType        PACKAGE         WILDCARD        WILDCARD_STAR   asInstanceOf    isInstanceOf    toString        

scala> reflect.runtime.universe.nme.<TAB>
CONSTRUCTOR           EMPTY                 ERROR                 LOCAL_SUFFIX_STRING   NameType              PACKAGE               
ROOTPKG               WILDCARD              asInstanceOf          isInstanceOf          toString      

@puffnfresh
Copy link
Author

@retronym that's much better. Thanks heaps!

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