summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurak Emir <emir@epfl.ch>2007-08-15 17:01:29 +0000
committerBurak Emir <emir@epfl.ch>2007-08-15 17:01:29 +0000
commitcbba5153da6cb1e6ef9f58fb8f1eb7c284841f11 (patch)
tree0a76288db6d1e36dcadf17c145311314e2e90eff
parent6b573ed92f9f160de1b2733d2547e8a72c989564 (diff)
downloadscala-cbba5153da6cb1e6ef9f58fb8f1eb7c284841f11.tar.gz
scala-cbba5153da6cb1e6ef9f58fb8f1eb7c284841f11.tar.bz2
scala-cbba5153da6cb1e6ef9f58fb8f1eb7c284841f11.zip
fixed Philipp's bug #1256 for real this time, u...
fixed Philipp's bug #1256 for real this time, use switch for characters (includes ugly boxing bug workaround), use StdNames in CodeFactory
-rw-r--r--src/compiler/scala/tools/nsc/matching/CodeFactory.scala11
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala140
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternMatchers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--test/files/run/unapply.scala16
6 files changed, 145 insertions, 30 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
index ce19ae5446..f7b892d357 100644
--- a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
+++ b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
@@ -152,9 +152,13 @@ trait CodeFactory {
}
/** for tree of sequence type, returns tree that drops first i elements */
- final def seqDrop(sel:Tree, i: Int) = if (i == 0) sel else
- Apply(Select(Select(sel, "toList"), "drop"),
- List(Literal(Constant(i))))
+ final def seqDrop(sel:Tree, ix: Int) = if (ix == 0) sel else
+ Apply(Select(Select(sel, nme.toList), nme.drop),
+ List(Literal(Constant(ix))))
+
+ /** for tree of sequence type, returns tree that drops first i elements */
+ final def seqElement(sel:Tree, ix: Int) = if (ix == 0) sel else
+ Apply(Select(sel, sel.tpe.member(nme.apply)), List(Literal(Constant(ix))))
/** for tree of sequence type, returns boolean tree that has length i */
final def seqHasLength(sel: Tree, ntpe: Type, i: Int) =
@@ -353,6 +357,7 @@ trait CodeFactory {
val sym = vd.symbol
val rt = new RefTraverser(sym)
rt.atOwner (theOwner) (rt.traverse(exp1))
+ //Console.println("hello, ref count = "+rt.nref+"/"+rt.nsafeRef)
rt.nref match {
case 0 =>
nremoved = nremoved + 1
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 0485a0d959..c56d767610 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -23,11 +23,13 @@ trait ParallelMatching {
import symtab.Flags
/** here, we distinguish which rewrite rule to apply
+ * @pre column does not contain alternatives (ensured by initRep)
*/
def MixtureRule(scrutinee:Symbol, column:List[Tree], rest:Rep): RuleApplication = {
- def isSimpleIntSwitch: Boolean = {
- (isSameType(scrutinee.tpe.widen, definitions.IntClass.tpe)/*||
- isSameType(scrutinee.tpe.widen, definitions.CharClass.tpe)*/) && {
+
+ def isSimpleSwitch: Boolean = {
+ (isSameType(scrutinee.tpe.widen, definitions.IntClass.tpe)||
+ 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
@@ -78,14 +80,16 @@ 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%%% MixArrayValue");
Console.println("STOP"); System.exit(-1); // EXPERIMENTAL
- //return new MixArrayValue(scrutinee, column, rest)
+ //return new MixSequence(scrutinee, column, rest)
}
- if(isSimpleIntSwitch) { DBG("\n%%% MixLiterals")
+ if(isSimpleSwitch) { DBG("\n%%% MixLiterals")
return new MixLiterals(scrutinee, column, rest)
}
+
if(settings_casetags && (column.length > 1) && isFlatCases(column)) {
DBG("flat cases!"+column+"\n"+scrutinee.tpe.typeSymbol.children+"\n"+scrutinee.tpe.member(nme.tag))
DBG("\n%%% MixCases")
@@ -105,6 +109,23 @@ trait ParallelMatching {
sealed trait RuleApplication {
def scrutinee:Symbol
+
+ // used in MixEquals and MixSequence
+ final protected def repWithoutHead(col:List[Tree],rest:Rep): Rep = {
+ var fcol = col.tail
+ var frow = rest.row.tail
+ val nfailrow = new ListBuffer[Row]
+ while(fcol ne Nil) {
+ val p = fcol.head
+ frow.head match {
+ case Row(pats,binds,g,bx) => nfailrow += Row(p::pats,binds,g,bx)
+ }
+ fcol = fcol.tail
+ frow = frow.tail
+ }
+ Rep(scrutinee::rest.temp, nfailrow.toList)
+ }
+
/** translate outcome of the rule application into code (possible involving recursive application of rewriting) */
def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree
}
@@ -230,7 +251,7 @@ trait ParallelMatching {
Row(column(tagIndexPairs.index)::pats, nbindings, g, bx)
}
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = {
+ final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree = {
val (branches, defaultV, default) = getTransition // tag body pairs
DBG("[[mix cases transition: branches \n"+(branches.mkString("","\n","")+"\ndefaults:"+defaultV+" "+default+"]]"))
@@ -338,7 +359,7 @@ trait ParallelMatching {
}
}
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = {
+ final def tree(implicit handleOuter: Tree=>Tree, 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, handleOuter)) }
@@ -350,10 +371,19 @@ trait ParallelMatching {
makeIf(Equals(Ident(this.scrutinee),lit), body, ndefault)
} else {
val defCase = CaseDef(mk_(definitions.IntClass.tpe), EmptyTree, ndefault)
- var selector:Tree = Ident(this.scrutinee)
- if(isSameType(this.scrutinee.tpe.widen, definitions.CharClass.tpe))
- selector = gen.mkAsInstanceOf(selector, definitions.IntClass.tpe)
- Match(selector, cases ::: defCase :: Nil)
+
+
+ if(isSameType(this.scrutinee.tpe.widen, definitions.CharClass.tpe)) {
+ val zz = newVar(this.scrutinee.pos, this.scrutinee.tpe)
+ // the valdef is a workaround for a bug in boxing -- Utility.parseCharRef contains an instance
+ // where erasure forgets the char to int conversion and emits Int.unbox in the scrutinee position
+ // of the match. This then fails at runtime, because it encounters a boxed Character, not boxedq Int
+ return Block(
+ List(typedValDef(zz, Ident(this.scrutinee))),
+ Match(gen.mkAsInstanceOf(Ident(zz), definitions.IntClass.tpe), cases ::: defCase :: Nil)
+ )
+ }
+ return Match(Ident(this.scrutinee), cases ::: defCase :: Nil)
}
} /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
} /* MixLiterals */
@@ -461,25 +491,87 @@ trait ParallelMatching {
} /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
} /* MixUnapply */
+ /** handle sequence pattern and ArrayValue
+ class MixSequence(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends RuleApplication {
+ // context (to be used in IF), success and failure Rep
+ final def getTransition(implicit theOwner: Symbol): (Tree => Tree => Tree, Rep, Rep) = {
+
+ assert(isSubType(scrutinee.tpe, column.head.tpe), "problem "+scrutinee.tpe+" not <: "+column.head.tpe)
+
+ val treeAsSeq =
+ if(!isSubType(scrutinee.tpe, column.head.tpe))
+ typed(gen.mkAsInstanceOf(gen.mkAttributedRef(scrutinee), column.head.tpe, true))
+ else
+ gen.mkAttributedRef(scrutinee)
+
+ val failRep = repWithoutHead(column,rest)
+
+ column.head match {
+ case av @ ArrayValue(_, xs) =>
+
+ var childpats = new ListBuffer[Tree]
+ var bindings = new ListBuffer[Tree]
+ var vs = new ListBuffer[Symbol]
+ var ix = 0
+
+ // if is right ignoring, don't want last one
+ var ys = if(isRightIgnoring(av)) xs.take(xs.length-1) else xs; while(ys ne Nil) {
+ val p = ys.head
+ childpats += p
+ val temp = newVar(p.pos, p.tpe)
+ Console.println("new temp:"+temp+":"+temp.tpe)
+ Console.println("seqelem:"+seqElement(treeAsSeq.duplicate, ix))
+ vs += temp
+ bindings += typedValDef(temp, seqElement(treeAsSeq.duplicate, ix))
+ ix += 1
+ ys = ys.tail
+ }
+
+ val childpatList = childpats.toList
+ val nrows = rest.row.map {
+ case Row(pats,subst,g,b) => Row(childpatList ::: pats,subst,g,b)
+ }
+ val succRep = Rep( vs.toList ::: rest.temp, nrows)
+
+ if(isRightIgnoring(av)) { // contains a _* at the end
+ val minlen = xs.length-1;
+
+ //typedValDef(casted, treeAsSeq.duplicate) :: bindings
+
+ val tempTail = newVar(xs.last.pos, xs.last.tpe)
+ bindings += typedValDef(tempTail, seqDrop(treeAsSeq.duplicate, minlen))
+
+ val cond = seqLongerThan(treeAsSeq.duplicate, column.head.tpe, minlen)
+
+ return ({thenp:Tree => {elsep:Tree =>
+ makeIf(cond, squeezedBlock(bindings.toList, thenp), elsep)
+ }}, succRep, failRep)
+ }
+
+ // fixed length
+ val cond = seqHasLength(treeAsSeq.duplicate, column.head.tpe, xs.length)
+ return ({thenp:Tree => {elsep:Tree => makeIf(cond, thenp, elsep)}}, succRep, failRep)
+ }
+ }
+
+ final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = {
+ val (cx,srep,frep) = this.getTransition
+ val succ = repToTree(srep, handleOuter)
+ val fail = repToTree(frep, handleOuter)
+ cx(succ)(fail)
+ }
+
+ }
+ */
class MixEquals(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends RuleApplication {
+ /** condition (to be used in IF), success and failure Rep */
final def getTransition(implicit theOwner: Symbol): (Tree, Rep, Rep) = {
val nmatrix = rest
val vlue = column.head.tpe match {
case TypeRef(_,_,List(SingleType(pre,sym))) =>
gen.mkAttributedRef(pre,sym)
}
- var fcol = column.tail
- var frow = rest.row.tail
- val nfailrow = new ListBuffer[Row]
- while(fcol ne Nil) {
- val p = fcol.head
- frow.head match {
- case Row(pats,binds,g,bx) => nfailrow += Row(p::pats,binds,g,bx)
- }
- fcol = fcol.tail
- frow = frow.tail
- }
- val nfail = Rep(scrutinee::rest.temp, nfailrow.toList)
+ val nfail = repWithoutHead(column,rest)
return (typed{ Equals(Ident(scrutinee) setType scrutinee.tpe, vlue) }, rest, nfail)
}
diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
index 8b44b773ad..dc0ce77db7 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
@@ -287,9 +287,9 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par
case ArrayValue(_,xs) => CantHandleSeq
//@todo
- //case ArrayValue(_,xs) => isImplemented(xs) //CantHandleSeq // DEBUG
+ //case av @ ArrayValue(_,xs) => if(isRightIgnoring(av)) CantHandleSeq else null // DEBUG
//case Star(t) => isImplemented(t) //can't happen/ excluded by Transmatcher:isregular
- //case Sequence(trees) =>can't happen/ only appear below ArrayValue
+ //case Sequence(trees) =>can't happen/ only appear below ArrayValue
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index c2e70528fc..51b76bd637 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -258,6 +258,7 @@ trait StdNames {
val classOf = newTermName("classOf")
val coerce = newTermName("coerce")
val defaultValue = newTermName("defaultValue")
+ val drop = newTermName("drop")
val dummy = newTermName("$dummy")
val elem = newTermName("elem")
val elements = newTermName("elements")
@@ -315,6 +316,7 @@ trait StdNames {
val send = newTermName("send")
val synchronized_ = newTermName("synchronized")
val tail = newTermName("tail")
+ val toList = newTermName("toList")
val toString_ = newTermName("toString")
val that = newTermName("that")
val that1 = newTermName("that1")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 4fe2159a34..4b6e3ce9db 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1659,7 +1659,7 @@ trait Typers { self: Analyzer =>
//Console.println(" sym="+sym+" "+" .isPackageClass="+sym.isPackageClass+" .isModuleClass="+sym.isModuleClass);
//Console.println(" funsymown="+fun.symbol.owner+" .isClass+"+fun.symbol.owner.isClass);
//Console.println(" contains?"+sym.tpe.decls.lookup(fun.symbol.name));
- if(sym != fun.symbol.owner && sym.isPackageClass /*(1)*/ ) { // (1) see 'files/pos/unapplyVal.scala'
+ if(sym != fun.symbol.owner && (sym.isPackageClass||sym.isModuleClass) /*(1)*/ ) { // (1) see 'files/pos/unapplyVal.scala'
if(fun.symbol.owner.isClass) {
mkThisType(fun.symbol.owner)
} else {
diff --git a/test/files/run/unapply.scala b/test/files/run/unapply.scala
index 416f8174f4..b4efbda9fa 100644
--- a/test/files/run/unapply.scala
+++ b/test/files/run/unapply.scala
@@ -115,3 +115,19 @@ object StreamFoo extends TestCase("unapply for Streams") with Assert {
assertEquals(sum(str), 6)
}
}
+
+object Test1256 extends TestCase("1256") {
+ class Sync {
+ def unapply(scrut: Any): Boolean = false
+ }
+
+ class Buffer {
+ val Get = new Sync
+
+ val jp: PartialFunction[Any, Any] = {
+ case Get() =>
+ }
+ }
+
+ override def runTest { assertFalse((new Buffer).jp.isDefinedAt(42)) }
+}