summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurak Emir <emir@epfl.ch>2007-08-24 14:50:54 +0000
committerBurak Emir <emir@epfl.ch>2007-08-24 14:50:54 +0000
commite032ccba0e0ccd7dee64adb76604621e20f61d01 (patch)
tree1579514ded3f8cdaf0b27204294592bc55a1d0a4
parente07c5695f30c8e56a1fb389a8a1dab8fb7240ee9 (diff)
downloadscala-e032ccba0e0ccd7dee64adb76604621e20f61d01.tar.gz
scala-e032ccba0e0ccd7dee64adb76604621e20f61d01.tar.bz2
scala-e032ccba0e0ccd7dee64adb76604621e20f61d01.zip
fixed build, better compilation of literal patt...
fixed build, better compilation of literal patterns to switch (supports variable binding)
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala3
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala133
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternMatchers.scala5
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala15
5 files changed, 120 insertions, 57 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 233fb09e0c..86e40d77ee 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -434,6 +434,9 @@ trait TypeKinds { self: ICodes =>
case AnnotatedType(attribs, tp) =>
toTypeKind(tp)
+ //case WildcardType => // bq: useful hack when wildcard types come here
+ // REFERENCE(definitions.ObjectClass)
+
case _ =>
abort("Unknown type: " + t)
}
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 89e856f08d..e21ebc42c4 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -40,7 +40,7 @@ trait ParallelMatching {
isSameType(scrutinee.tpe.widen, definitions.CharClass.tpe)) && {
var xs = column; while(!xs.isEmpty) { // forall
val h = xs.head
- if(h.isInstanceOf[Literal] || isDefaultPattern(h)) { xs = xs.tail } else return false
+ if(strip2(h).isInstanceOf[Literal] || isDefaultPattern(h)) { xs = xs.tail } else return false
}
return true
}}
@@ -88,7 +88,7 @@ trait ParallelMatching {
*/
if(isEqualsPattern(column.head.tpe)) { DBG("\n%%% MixEquals");
return new MixEquals(scrutinee, column, rest)
- }
+ }
// the next condition is never true, @see isImplemented/CantHandleSeq
if(column.head.isInstanceOf[ArrayValue]) { DBG("\n%%% MixSequence");
throw new FatalError("not implemented yet");
@@ -348,8 +348,30 @@ trait ParallelMatching {
}
}
- private def sanity(pos:Position,pvars:Set[Symbol]) {
- if(!pvars.isEmpty) cunit.error(pos, "nonsensical variable binding")
+ var varMap: List[(Int,List[Symbol])] = Nil
+
+ private def sanity(pos:Position, tag: Int, pvars:List[Symbol]) {
+ varMap = (tag,pvars)::varMap
+ //if(!pvars.isEmpty) cunit.error(pos, "nonsensical variable binding")
+ }
+ /* // eager
+ private def bindVars(Tag:Int, body:Tree): Tree = {
+ def myBindVars(rest:List[(Int,List[Symbol])], vd: List[Tree]): Tree = rest match {
+ case Nil => if(vd eq Nil) body else Block(vd,body)
+ case (Tag,vs)::xs => myBindVars(xs, (vs.map { v => typedValDef(v,mkIdent(scrutinee)) }):::vd)
+ case (_, vs)::xs => myBindVars(xs, vd)
+ }
+ myBindVars(varMap, Nil)
+ }
+ */
+ //lazy
+ private def bindVars(Tag:Int, orig: Binding): Binding = {
+ def myBindVars(rest:List[(Int,List[Symbol])], bnd: Binding): Binding = rest match {
+ case Nil => bnd
+ case (Tag,vs)::xs => myBindVars(xs, bnd.add(vs.elements, scrutinee))
+ case (_, vs)::xs => myBindVars(xs, bnd)
+ }
+ myBindVars(varMap, orig)
}
/*block*/{
@@ -357,8 +379,8 @@ trait ParallelMatching {
var i = 0;
while(xs ne Nil) { // forall
strip(xs.head) match {
- case (pvars, p @ Literal(Constant(c:Int))) => sanity(p.pos, pvars); insertTagIndexPair(c,i)
- case (pvars, p @ Literal(Constant(c:Char))) => sanity(p.pos, pvars); insertTagIndexPair(c.toInt,i)
+ case (pvars, p @ Literal(Constant(c:Int))) => sanity(p.pos, c , definedVars(xs.head)); insertTagIndexPair(c,i)
+ case (pvars, p @ Literal(Constant(c:Char))) => sanity(p.pos, c.toInt, definedVars(xs.head)); insertTagIndexPair(c.toInt,i)
case (pvars, p ) if isDefaultPattern(p) => insertDefault(i,pvars)
}
i += 1
@@ -369,7 +391,10 @@ trait ParallelMatching {
final def tree(implicit theOwner: Symbol, failTree: Tree): Tree = {
val (branches, defaultV, defaultRepOpt) = this.getTransition // tag body pairs
DBG("[[mix literal transition: branches \n"+(branches.mkString("","\n",""))+"\ndefaults:"+defaultV+"\n"+defaultRepOpt+"\n]]")
- val cases = branches map { case (tag, rep) => CaseDef(Literal(tag), EmptyTree, repToTree(rep)) }
+ val cases = branches map {
+ case (tag, r) =>
+ CaseDef(Literal(tag), EmptyTree, repToTree(rep.make(r.temp, r.row map { case Row(pat,bnd,g,bx) => Row(pat,bindVars(tag,bnd),g,bx) })))
+ }
var ndefault = if(defaultRepOpt.isEmpty) failTree else repToTree(defaultRepOpt.get)
renamingBind(defaultV, this.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee
@@ -573,7 +598,7 @@ trait ParallelMatching {
// @todo: equals test for same constant
class MixEquals(val scrutinee:Symbol, val column:List[Tree], val rest:Rep)(implicit rep:RepFactory) extends RuleApplication(rep) {
/** condition (to be used in IF), success and failure Rep */
- final def getTransition(implicit theOwner: Symbol): (Tree, Rep, Rep) = {
+ final def getTransition(implicit theOwner: Symbol): (Tree, Rep, Symbol, Rep) = {
val nmatrix = rest
val vlue = (column.head.tpe: @unchecked) match {
case TypeRef(_,_,List(SingleType(pre,sym))) =>
@@ -581,29 +606,30 @@ trait ParallelMatching {
}
assert(vlue.tpe ne null)
val nsuccFst = rest.row.head match { case Row(pats,bnd,g,b) => Row(EmptyTree::pats,bnd,g,b) }
- val nsuccRow = nsuccFst :: (column.tail.zip(rest.row.tail) map { case (p, Row(pats,bnd,g,b)) => Row(p::pats,bnd,g,b) })
+ //val nsuccRow = nsuccFst :: (column.tail.zip(rest.row.tail) map { case (p, Row(pats,bnd,g,b)) => Row(p::pats,bnd,g,b) })
+ val fLabel = theOwner.newLabel(scrutinee.pos, cunit.fresh.newName("failCont%")) // warning, untyped
+ val sx = rep.shortCut(fLabel) // register shortcut
+ val nsuccRow = nsuccFst :: Row(getDummies( 1 /*scrutinee*/ + rest.temp.length), NoBinding, EmptyTree, sx) :: Nil
+
+
+ // todo: optimize if no guard, and no further tests
val nsucc = rep.make(scrutinee :: rest.temp, nsuccRow)
val nfail = repWithoutHead(column,rest)
- return (typed{ Equals(mkIdent(scrutinee) setType scrutinee.tpe, vlue) }, nsucc, nfail)
+
+ return (typed{ Equals(mkIdent(scrutinee) setType scrutinee.tpe, vlue) }, nsucc, fLabel, nfail)
}
final def tree(implicit theOwner: Symbol, failTree: Tree) = {
- val (cond,srep,frep) = this.getTransition
+ val (cond, srep, fLabel, frep) = this.getTransition
//Console.println("MixEquals::tree -- cond "+cond)
- val cond2 = try{
- typed { rep.handleOuter(cond) }
- } catch {
- case e =>
- Console.println("failed to type-check cond2")
- Console.println("cond: "+cond)
- Console.println("cond2: "+rep.handleOuter(cond))
- throw e
- }
-
+ val cond2 = typed { rep.handleOuter(cond) }
+ DBG("MixEquals, srep = "+srep)
+ DBG("MixEquals, frep = "+frep)
+ val fail = typed { repToTree(frep) }
+ fLabel setInfo (new MethodType(Nil, fail.tpe))
val succ = repToTree(srep)
- val fail = repToTree(frep)
try {
- typed{ If(cond2, succ, fail) }
+ typed{ If(cond2, succ, LabelDef(fLabel, Nil, fail)) }
} catch {
case e =>
Console.println("failed to type-check If")
@@ -736,7 +762,7 @@ trait ParallelMatching {
/** returns casted symbol, success matrix and optionally fail matrix for type test on the top of this column */
final def getTransition(implicit theOwner: Symbol): (Symbol, Rep, Option[Rep]) = {
- //Console.println("*** getTransition! of "+this.toString)
+ //DBG("*** getTransition! of "+this.toString)
// the following works for type tests... what fudge is necessary for value comparisons?
// type test
casted = if(scrutinee.tpe =:= headPatternType) scrutinee else newVar(scrutinee.pos, headPatternType)
@@ -767,8 +793,8 @@ trait ParallelMatching {
val nsubst = osubst.add(vs.elements, casted)
Row(pats ::: opats, nsubst, og, bx)
}
- //DBG("ntemps = "+ntemps.mkString("[["," , ","]]"))
- //DBG("ntriples = "+ntriples.mkString("[[\n","\n, ","\n]]"))
+ DBG("ntemps = "+ntemps.mkString("[["," , ","]]"))
+ DBG("ntriples = "+ntriples.mkString("[[\n","\n, ","\n]]"))
rep.make(ntemps, ntriples) /*setParent this*/
}
// fails => transition to translate(remaining)
@@ -780,7 +806,7 @@ trait ParallelMatching {
}
if(ntriples.isEmpty) None else Some(rep.make(ntemps, ntriples))
}
- //DBG("nmatrixFail = \n\n"+nmatrixFail)
+ DBG("nmatrixFail = \n\n"+nmatrixFail)
(casted, nmatrix, nmatrixFail)
} /* getTransition(implicit theOwner: Symbol): (Symbol, Rep, Option[Rep]) */
@@ -1000,13 +1026,11 @@ trait ParallelMatching {
case MethodType(fmls,_) =>
if (fmls.length != args.length) { // sanity check
cunit.error(targets(bx).pos, "consistency problem in target generation ! I have args "+args+" and need to jump to a label with fmls "+fmls)
- //System.exit(-1)
throw FatalError("consistency problem")
}
for((f,a) <- fmls.zip(args.toList)) {
if(!(a.tpe <:< f)) {
cunit.error(targets(bx).pos, "consistency problem ! "+a.tpe+" "+f)
- //System.exit(-1)
throw FatalError("consistency problem")
}
}
@@ -1051,17 +1075,28 @@ trait ParallelMatching {
var pats:List[Tree] = Nil
var indexOfAlternative = -1
var j = 0; while(opats ne Nil) {
+ var opat = opats.head // original pattern
//Console.println("opats.head = "+opats.head.getClass)
- opats.head match {
- case p if isAlternative(p) && indexOfAlternative == -1 =>
- indexOfAlternative = j
- unchanged = false
- pats = p :: pats
+ val (vars,strippedPat) = strip(opat)
+ val vs = vars.toList
+ strippedPat match {
+ case p @ Alternative(ps) =>
+ if(indexOfAlternative == -1) {
+ unchanged = false
+ indexOfAlternative = j
+ }
+ pats = opat :: pats
+
+ case _ if !vs.isEmpty =>
+ pats = opat :: pats // strange but true: Bind node is deferred
case typat @ Typed(p:UnApply,tpt) =>
pats = (if (temp(j).tpe <:< tpt.tpe) p else typat)::pats // what about the null-check?
- case o @ Ident(n) if n != nme.WILDCARD =>
+ case Ident(nme.WILDCARD) | EmptyTree | _:Literal | _:Typed =>
+ pats = opat :: pats
+
+ case o @ Ident(n) => // n != nme.WILDCARD
/*
Console.println("/'''''''''''' 1"+o.tpe)
Console.println("/'''''''''''' 2"+o.symbol)
@@ -1087,10 +1122,8 @@ trait ParallelMatching {
}
val p = Ident(nme.WILDCARD) setType tpe
val q = Typed(p, TypeTree(tpe)) setType tpe
- pats = q::pats
+ pats = (makeBind( vs, q) setType tpe) :: pats
- case o @ Ident(nme.WILDCARD) =>
- pats = o::pats
case o @ Select(stor,_) =>
val stpe =
@@ -1103,7 +1136,7 @@ trait ParallelMatching {
singleType(NoPrefix, o.symbol) // equals-check
}
val p = Ident(nme.WILDCARD) setType stpe
- val q = Typed(p, TypeTree(stpe)) setType stpe
+ val q = makeBind(vs,Typed(p, TypeTree(stpe)) setType stpe) setType stpe
pats = q::pats
case UnApply(Apply(TypeApply(sel @ Select(stor, nme.unapplySeq),List(tptArg)),_),ArrayValue(_,xs)::Nil) if(stor.symbol eq definitions.ListModule) =>
@@ -1112,11 +1145,12 @@ trait ParallelMatching {
temp(j).setFlag(symtab.Flags.TRANS_FLAG)
val listType = typeRef(mkThisType(definitions.ScalaPackage), definitions.ListClass, List(tptArg.tpe))
val nmlzdPat = normalizedListPattern(xs, tptArg.tpe)
- pats = nmlzdPat :: pats
+ pats = makeBind(vs, nmlzdPat) :: pats
case ua @ UnApply(Apply(fn, _), arg) =>
fn.tpe match {
case MethodType(List(argtpe,_*),_) =>
- pats = (if (temp(j).tpe <:< argtpe) ua else Typed(ua,TypeTree(argtpe)).setType(argtpe))::pats
+ val npat = (if (temp(j).tpe <:< argtpe) ua else Typed(ua,TypeTree(argtpe)).setType(argtpe))
+ pats = (makeBind(vs, npat) setType argtpe)::pats
}
/** something too tricky is going on if the outer types don't match
@@ -1163,27 +1197,24 @@ trait ParallelMatching {
//Console.println("here's the result: "+ttst)
val p = Ident(nme.WILDCARD) setType ttst
- val q = Typed(p, TypeTree(stpe)) setType ttst
+ val q = makeBind(vs,Typed(p, TypeTree(stpe)) setType ttst)
pats = q::pats
case Apply_Value(pre, sym) =>
val tpe = typeRef(NoPrefix, definitions.EqualsPatternClass, singleType(pre, sym)::Nil)
- val q = Typed(EmptyTree, TypeTree(tpe)) setType tpe
+ val q = makeBind(vs,Typed(EmptyTree, TypeTree(tpe)) setType tpe)
pats = q :: pats
case Apply_CaseClass_NoArgs(tpe) => // no-args case class pattern
- val q = Typed(EmptyTree, TypeTree(tpe)) setType tpe
+ val q = makeBind(vs, Typed(EmptyTree, TypeTree(tpe)) setType tpe)
pats = q :: pats
- case o @ Apply_CaseClass_WithArgs() => // case class pattern with args
- pats = o :: pats
+ case Apply_CaseClass_WithArgs() => // case class pattern with args
+ pats = opat :: pats
- case p @ ArrayValue(_,xs) =>
- assert(false) // inactive, @see PatternMatchers::isImplemented
+ case ArrayValue(_,xs) =>
+ assert(false) // inactive, @see PatternMatchers::isImplemented
- // it would be nice to get rid of the default case, but then have to treat Bind(_,_)
- case p =>
- pats = p :: pats
}
opats = opats.tail
j += 1
diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
index 1dd6541f9f..6a4f6b8a69 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
@@ -258,7 +258,7 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par
//Console.println(fn.symbol)
if(!xs.isEmpty) {
assert(false)
- return CantHandleApply // System.exit(-1); // this should never happen
+ return CantHandleApply // this should never happen
}
null
} else {
@@ -1126,10 +1126,7 @@ print()
typed { t } // //DEBUG
} catch {
case e =>
-
Console.println("failed with "+e.getMessage()+" on: "+t)
- //System.exit(-1)
- //null
t
}
}
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index 44b1d96f42..bc9c359502 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -15,6 +15,27 @@ trait PatternNodes { self: transform.ExplicitOuter =>
import global._
+ object TagIndexPair {
+ /** inserts tag and index, maintaining relative order of tags */
+ def insert(current: TagIndexPair, tag: Int, index: Int): TagIndexPair = {
+ if (current eq null)
+ new TagIndexPair(tag, index, null)
+ else if (tag > current.tag)
+ new TagIndexPair(current.tag, current.index, insert(current.next, tag, index))
+ else
+ new TagIndexPair(tag, index, current)
+ }
+ }
+
+ /** sorted, null-terminated list of (int,int) pairs */
+ class TagIndexPair(val tag: Int, val index: Int, val next: TagIndexPair) {
+
+ def find(tag: Int): Int =
+ if (this.tag == tag) index
+ else next.find(tag) // assumes argument can always be found
+
+ }
+
// --- misc methods
private val dummy1 = EmptyTree :: Nil
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ed796b9967..186abad06e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2721,8 +2721,19 @@ trait Typers { self: Analyzer =>
case UnApply(fun, args) =>
val fun1 = typed(fun)
- val args1 = List.mapConserve(args)(typedPattern(_, WildcardType))
- copy.UnApply(tree, fun1, args1) setType pt
+ var tpes = fun.symbol.name match {
+ case nme.unapply => unapplyTypeListFromReturnType (fun.tpe)
+ case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(fun.tpe)
+ }
+ var as = args; while(as ne Nil) { // bq: typing a pattern never changes the tree
+ typedPattern(as.head, tpes.head match {
+ case TypeRef(_,sym,targs) if sym eq definitions.RepeatedParamClass => targs.head
+ case tpe => tpe
+ })
+ as = as.tail; tpes = tpes.tail
+ }
+ //val args1 = List.mapConserve(args)(typedPattern(_, WildcardType))
+ copy.UnApply(tree, fun1, args) setType pt
case ArrayValue(elemtpt, elems) =>
typedArrayValue(elemtpt, elems)