package scala.tools.nsc
package matching
import transform.ExplicitOuter
import symtab.Flags
import scala.collection.mutable
trait Matrix extends MatrixAdditions {
self: ExplicitOuter with ParallelMatching =>
import global.{ typer => _, _ }
import analyzer.Typer
import CODE._
import Debug._
import Flags.{ SYNTHETIC, MUTABLE }
private[matching] val NO_EXHAUSTIVE = Flags.TRANS_FLAG
def handlePattern(
selector: Tree,
cases: List[CaseDef],
isChecked: Boolean,
context: MatrixContext): Tree =
{
import context._
TRACE("handlePattern", "(%s: %s) match { %s cases }", selector, selector.tpe, cases.size)
val matrixInit: MatrixInit = {
val v = copyVar(selector, isChecked, selector.tpe, "temp")
MatrixInit(List(v), cases, atPos(selector.pos)(MATCHERROR(v.ident)))
}
val matrix = new MatchMatrix(context) { lazy val data = matrixInit }
val mch = typer typed matrix.expansion.toTree
val dfatree = typer typed Block(matrix.data.valDefs, mch)
matrix.targets filter (_.unreached) foreach (cs => cunit.error(cs.body.pos, "unreachable code"))
tracing("handlePattern")(matrix optimize dfatree)
}
case class MatrixContext(
cunit: CompilationUnit,
handleOuter: Tree => Tree,
typer: Typer,
owner: Symbol,
matchResultType: Type)
extends Squeezer
{
private def ifNull[T](x: T, alt: T) = if (x == null) alt else x
private def flags(checked: Boolean) = if (checked) Nil else List(NO_EXHAUSTIVE)
private val _syntheticSyms = mutable.HashSet[Symbol]()
def clearSyntheticSyms() = {
_syntheticSyms foreach (_ resetFlag (NO_EXHAUSTIVE|MUTABLE))
if (settings.debug.value)
log("Cleared NO_EXHAUSTIVE/MUTABLE on " + _syntheticSyms.size + " synthetic symbols.")
_syntheticSyms.clear()
}
def recordSyntheticSym(sym: Symbol): Symbol = {
_syntheticSyms += sym
if (_syntheticSyms.size > 25000) {
cunit.error(owner.pos, "Sanity check failed: over 25000 symbols created for pattern match.")
abort("This is a bug in the pattern matcher.")
}
sym
}
case class MatrixInit(
roots: List[PatternVar],
cases: List[CaseDef],
default: Tree
) {
def tvars = roots map (_.lhs)
def valDefs = roots map (_.valDef)
override def toString() = "MatrixInit(roots = %s, %d cases)".format(pp(roots), cases.size)
}
implicit def pvlist2pvgroup(xs: List[PatternVar]): PatternVarGroup =
PatternVarGroup(xs)
object PatternVarGroup {
def apply(xs: PatternVar*) = new PatternVarGroup(xs.toList)
def apply(xs: List[PatternVar]) = new PatternVarGroup(xs)
def fromBindings(vlist: List[Binding], freeVars: List[Symbol] = Nil) = {
def vmap(v: Symbol): Option[Binding] = vlist find (_.pvar eq v)
val info =
if (freeVars.isEmpty) vlist
else (freeVars map vmap).flatten
val xs =
for (Binding(lhs, rhs) <- info) yield
new PatternVar(lhs, Ident(rhs) setType lhs.tpe, !(rhs hasFlag NO_EXHAUSTIVE))
new PatternVarGroup(xs)
}
}
val emptyPatternVarGroup = PatternVarGroup()
class PatternVarGroup(val pvs: List[PatternVar]) {
def syms = pvs map (_.sym)
def valDefs = pvs map (_.valDef)
def idents = pvs map (_.ident)
def extractIndex(index: Int): (PatternVar, PatternVarGroup) = {
val (t, ts) = self.extractIndex(pvs, index)
(t, PatternVarGroup(ts))
}
def isEmpty = pvs.isEmpty
def size = pvs.size
def head = pvs.head
def ::(t: PatternVar) = PatternVarGroup(t :: pvs)
def :::(ts: List[PatternVar]) = PatternVarGroup(ts ::: pvs)
def ++(other: PatternVarGroup) = PatternVarGroup(pvs ::: other.pvs)
def apply(i: Int) = pvs(i)
def zipWithIndex = pvs.zipWithIndex
def indices = pvs.indices
def map[T](f: PatternVar => T) = pvs map f
def filter(p: PatternVar => Boolean) = PatternVarGroup(pvs filter p)
override def toString() = pp(pvs)
}
class PatternVar(val lhs: Symbol, val rhs: Tree, val checked: Boolean) {
def sym = lhs
def tpe = lhs.tpe
lazy val ident = typer typed Ident(lhs)
lazy val valDef = typer typedValDef ValDef(lhs, rhs)
override def toString() = "%s: %s = %s".format(lhs, tpe, rhs)
}
def specialVar(lhs: Symbol, checked: Boolean) =
new PatternVar(lhs, EmptyTree, checked)
def copyVar(
root: Tree,
checked: Boolean,
_tpe: Type = null,
label: String = "temp"): PatternVar =
{
val tpe = ifNull(_tpe, root.tpe)
val name = cunit.freshTermName(label)
val sym = newVar(root.pos, tpe, flags(checked), name)
tracing("copy")(new PatternVar(sym, root, checked))
}
def createVar(tpe: Type, f: Symbol => Tree, checked: Boolean) = {
val lhs = newVar(owner.pos, tpe, flags(checked))
val rhs = f(lhs)
tracing("create")(new PatternVar(lhs, rhs, checked))
}
def createLazy(tpe: Type, f: Symbol => Tree, checked: Boolean) = {
val lhs = newVar(owner.pos, tpe, Flags.LAZY :: flags(checked))
val rhs = f(lhs)
tracing("createLazy")(new PatternVar(lhs, rhs, checked))
}
private def newVar(
pos: Position,
tpe: Type,
flags: List[Long] = Nil,
name: TermName = null): Symbol =
{
val n = if (name == null) cunit.freshTermName("temp") else name
recordSyntheticSym(owner.newVariable(pos, n) setInfo tpe setFlag (SYNTHETIC.toLong /: flags)(_|_))
}
}
}