1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
/* NSC -- new Scala compiler
* Copyright 2005-2007 LAMP/EPFL
* Copyright 2007 Google Inc. All Rights Reserved.
* Author: bqe@google.com (Burak Emir)
*/
// $Id$
package scala.tools.nsc.matching
/** Translation of pattern matching
*
* @author Burak Emir
*/
trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with ParallelMatching with CodeFactory =>
import global.{ typer => _, _ }
import analyzer.Typer;
import definitions._
import symtab.Flags
var cunit: CompilationUnit = _ // memory leak?
var resultType: Type = _
// cache these
final val settings_debug = settings.debug.value
// check special case Seq(p1,...,pk,_*)
protected def isRightIgnoring(p: ArrayValue): Boolean = {
def isDefaultStar(tree: Tree): Boolean = tree match {
case Bind(_, q) => isDefaultStar(q)
case Star(Ident(nme.WILDCARD)) => true
case _ => false
}
!p.elems.isEmpty && isDefaultStar(p.elems.last)
}
/** handles all translation of pattern matching
*/
def handlePattern(selector: Tree, cases: List[CaseDef], doCheckExhaustive: Boolean, owner: Symbol, handleOuter: Tree => Tree)(implicit typer : Typer): Tree = {
DBG("****")
DBG("**** initalize, selector = "+selector+" selector.tpe = "+selector.tpe)
DBG("**** doCheckExhaustive == "+doCheckExhaustive)
implicit val theOwner = owner
implicit val rep = new RepFactory(handleOuter)
def caseIsOk(c: CaseDef) = c match {
case CaseDef(_: Apply, _, _) => true
case CaseDef(Ident(nme.WILDCARD), _, _) => true
case _ => false
}
def doApply(fn: Tree) = (fn.symbol eq selector.tpe.decls.lookup(nme.CONSTRUCTOR)) && (cases forall caseIsOk)
def processApply(app: Apply): (List[Symbol], List[Tree], Tree) = {
val Apply(fn, args) = app
val (tmps, vds) = List.unzip(
for ((ti, i) <- args.zipWithIndex) yield {
val v = newVar(ti.pos, cunit.fresh.newName(ti.pos, "tp"), selector.tpe.typeArgs(i))
if (!doCheckExhaustive) v setFlag Flags.TRANS_FLAG
(v, typedValDef(v, ti))
}
)
(tmps, vds, ThrowMatchError(selector.pos, copy.Apply(app, fn, tmps map mkIdent)))
}
// sets temporaries, variable declarations, and the fail tree
val (tmps, vds, theFailTree) = selector match {
case app @ Apply(fn, _) if isTupleType(selector.tpe) && doApply(fn) => processApply(app)
case _ =>
val root: Symbol = newVar(selector.pos, selector.tpe)
if (!doCheckExhaustive)
root setFlag Flags.TRANS_FLAG
val vdef: Tree = typer.typed(ValDef(root, selector))
val failTree: Tree = ThrowMatchError(selector.pos, mkIdent(root))
(List(root), List(vdef), failTree)
}
implicit val fail: Tree = theFailTree
val irep = initRep(tmps, cases, rep)
val mch = typer.typed(repToTree(irep))
var dfatree = typer.typed(Block(vds, mch))
for ((cs, bx) <- cases.zipWithIndex)
if (!rep.isReached(bx)) cunit.error(cs.body.pos, "unreachable code")
dfatree = rep.cleanup(dfatree)
resetTrav.traverse(dfatree)
dfatree
}
object resetTrav extends Traverser {
override def traverse(x: Tree): Unit = x match {
case (vd: ValDef) => if (vd.symbol hasFlag Flags.SYNTHETIC) {
vd.symbol resetFlag Flags.TRANS_FLAG
vd.symbol resetFlag Flags.MUTABLE
}
case _ =>
super.traverse(x)
}
}
}
|