summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sources/scala/tools/scalac/ast/parser/Parser.scala4
-rw-r--r--sources/scala/tools/scalac/ast/parser/PatternNormalizer.scala9
-rw-r--r--sources/scala/tools/scalac/transformer/TransMatch.scala141
-rw-r--r--sources/scala/tools/scalac/transformer/matching/PatternMatcher.scala97
-rw-r--r--sources/scala/tools/scalac/transformer/matching/PatternNode.scala20
-rw-r--r--sources/scalac/ast/Transformer.java.tmpl19
-rw-r--r--test/files/run/regularpatmat.check5
-rw-r--r--test/files/run/regularpatmat.scala39
8 files changed, 284 insertions, 50 deletions
diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala
index ae5d490ffe..90943e8fd8 100644
--- a/sources/scala/tools/scalac/ast/parser/Parser.scala
+++ b/sources/scala/tools/scalac/ast/parser/Parser.scala
@@ -1743,7 +1743,9 @@ class Parser(unit: CompilationUnit) {
var lhs = new myTreeList();
do {
s.nextToken();
- lhs.append(pattern2());
+ val pat = pattern2();
+ pN.check(pat); // bq: to catch `val y + = 3' bug #371
+ lhs.append(pat);
} while (s.token == COMMA);
val tp = typedOpt();
val rhs = if (tp == Tree.Empty || s.token == EQUALS) equalsExpr() else Tree.Empty;
diff --git a/sources/scala/tools/scalac/ast/parser/PatternNormalizer.scala b/sources/scala/tools/scalac/ast/parser/PatternNormalizer.scala
index 17cee21251..18b07049b3 100644
--- a/sources/scala/tools/scalac/ast/parser/PatternNormalizer.scala
+++ b/sources/scala/tools/scalac/ast/parser/PatternNormalizer.scala
@@ -135,7 +135,11 @@ package scala.tools.scalac.ast.parser {
def check( pat:Tree ):boolean = {
this.boundVars = new HashMap();
+ if(TreeInfo.isSequenceValued( pat ))
+ unit.error( pat.pos, "sequence pattern not allowed here");
+
//reject top-level sequence patterns
+ /*
pat match {
case Tree$Sequence( _ ) =>
unit.error( pat.pos, "sequences not allowed here"); false;
@@ -151,8 +155,13 @@ package scala.tools.scalac.ast.parser {
};
i = i + 1
}
+
+ case Tree$Bind(_, x) =>
+ if(TreeInfo.isSequenceValued( pat ))
+ unit.error( pat.pos, "sequence pattern not allowed here");
case _ =>
}
+ */
// reject deep binding
if( TreeInfo.isRegularPattern( pat ) )
this.seqDepth = 0;
diff --git a/sources/scala/tools/scalac/transformer/TransMatch.scala b/sources/scala/tools/scalac/transformer/TransMatch.scala
index f654b609b8..9db79f3a32 100644
--- a/sources/scala/tools/scalac/transformer/TransMatch.scala
+++ b/sources/scala/tools/scalac/transformer/TransMatch.scala
@@ -7,7 +7,7 @@
// $Id$
import java.io._;
-import java.util._;
+import java.util.HashMap;
import scalac.{Global => scalac_Global};
import scalac._;
import scalac.ast._;
@@ -53,7 +53,9 @@ class TransMatch( global:scalac_Global )
}
def isRegular(pat:Tree):Boolean = pat match {
- case Alternative(_) => true
+ //case Alternative(_) => true
+ case Alternative(trees) =>
+ isRegular(trees)
case Bind( n, pat1 ) =>
TreeInfo.isNameOfStarPattern( n )
|| TreeInfo.isEmptySequence( pat1 )
@@ -71,7 +73,7 @@ class TransMatch( global:scalac_Global )
}
def nilVariables( pat:Tree ) = {
- var res:scala.List[Symbol] = Nil;
+ var res:List[Symbol] = Nil;
def getNilVars1( ps:Array[Tree] ):scala.Unit = {
val z:Seq[Tree] = ps; z.elements.foreach( x => getNilVars( x ));
}
@@ -108,6 +110,130 @@ class TransMatch( global:scalac_Global )
}
}
+
+ // @pre cases are all nonregular
+ def removeAlterns(cases: Array[CaseDef]) = {
+
+ def lst2arr(l:List[Tree]):Array[Tree] = {
+ val res = new Array[Tree](l.length);
+ val it = l.elements; var i = 0; while(it.hasNext) {
+ res(i) = it.next;
+ i = i + 1;
+ }
+ res
+ }
+ def select(j:int, expanded:Array[List[Tree]]): List[List[Tree]] = {
+ if( j == expanded.length )
+ List(scala.Nil);
+ else {
+ val rest:List[List[Tree]] = select(j+1, expanded);
+ //expanded(j) map { x:Tree => rest map { xs:List[Tree] => x :: xs }}
+ for(val t <- expanded(j);
+ val zs <- rest)
+ yield t :: zs;
+ }
+ }
+
+ def remove(pat:Tree): List[Tree] = {
+ //Console.println("remove("+pat+"), currentOwner = "+currentOwner);
+ val res = pat.match {
+ case Alternative( branches ) => // no bind allowed!
+ val z: Seq[Tree] = branches;
+ List.flatten(z.toList.map( remove ));
+ case b @ Bind( n, pat ) =>
+ //Console.println("remove-Bind sym-owner: "+b.symbol().owner());
+ remove(pat) match {
+ case List(r) if (r eq pat) =>
+ List(b);
+ case zs =>
+ //Console.println("remove-Bind sym: "+b.symbol());
+ //Console.println("remove-Bind sym-type: "+b.symbol().getType());
+ //Console.println("rb-(case zs)"+zs);
+ zs map { x => //Console.println(b.symbol());
+ val r = new ExtBind(b.symbol(),x);
+ r.setType(b.getType());
+ //Console.println("rrrrr ="+ r.getType());
+ r
+ };
+ }
+ case Sequence( trees ) =>
+ val expanded = new Array[List[Tree]](trees.length);
+ var i = 0; while( i < trees.length) {
+ expanded(i) = remove(trees(i));
+ i = i + 1;
+ }
+ select(0, expanded) map { x:List[Tree] =>
+ //Console.println("remove:Sequence, type = "+pat.getType());
+ val res = Sequence(lst2arr(x)).setType(pat.getType());
+ //Console.println("remove:Sequence RETURNS "+res);
+ res
+ }
+
+ case Apply( fn, trees ) =>
+ val expanded = new Array[List[Tree]](trees.length);
+ var i = 0; while( i < trees.length) {
+ expanded(i) = remove(trees(i));
+ i = i + 1;
+ }
+
+ select(0, expanded) map { x => new Apply(fn, lst2arr(x))
+ .setType(pat.getType()) }
+
+ case Ident(_) => List(pat);
+ case Literal(_) => List(pat);
+ case Select(_,_) => List(pat);
+ case Typed(_,_) => List(pat);
+ case _ => error("in TransMatch.nilVariables: unknown node"+pat.getClass());
+
+
+ }
+ //Console.println("end remove("+pat+")");
+ res
+ }
+ val zs:Seq[CaseDef] = cases;
+
+ val ncases: List[List[Tree]] = zs.toList map {
+ x => x match {
+ case CaseDef(pat,guard,body) =>
+
+ //Console.println("removeAlterns - ("+x+"), currentOwner = "+currentOwner);
+ val sc = new SymbolCloner();
+
+ sc.owners.put(currentOwner,currentOwner);
+
+ val tc = new GenTreeCloner(global, Type.IdMap, sc) {
+
+ override def getSymbolFor(tree:Tree): Symbol = {
+ tree match {
+ case Bind(_,_) =>
+ val symbol = cloner.cloneSymbol(tree.symbol());
+
+ //System.out.println("TreeCloner: Bind"+symbol);
+ //System.out.println("TreeCloner: Bind - old owner "+tree.symbol().owner());
+ //System.out.println("TreeCloner: Bind - new owner "+symbol.owner());
+ //Console.println("in TreeCloner: type = "+symbol.getType());
+ symbol.setType(transform(symbol.getType()));
+ //Console.println("in TreeCloner: type (post) = "+symbol.getType());
+ //System.out.println("done TreeCloner: Bind"+symbol);
+ return symbol;
+ case _ =>
+ if(tree.definesSymbol())
+ tree.symbol()
+ else
+ super.getSymbolFor(tree);
+ }
+
+ }
+ }
+ remove(pat) map { x =>
+ val res = tc.transform(new CaseDef(x,guard,body));
+ /*Console.println(sc.owners);*/res}
+ }
+ }
+
+ lst2arr(List.flatten(ncases));
+ }
+
//val bsf = new scala.util.automaton.BerrySethi[ matching.PatternTest ]( pe );
def transform( root:Tree, cases:Array[CaseDef], restpe:Type ):Tree = {
@@ -156,13 +282,16 @@ class TransMatch( global:scalac_Global )
val pm = new matching.PatternMatcher( cunit );
pm.initialize(root, currentOwner, restpe, true );
try{
- pm.construct( cases.asInstanceOf[ Array[Tree] ] );
+ val ncases = removeAlterns(cases);
+ pm.construct( ncases.asInstanceOf[Array[Tree]] );
} catch {
case e:Throwable =>
+ e.printStackTrace();
Console.print("failed on pats "+scala.Iterator.fromArray(cases).toList.mkString("","\n","")+", message\n"+e.getMessage());
+ Console.print(" unit "+cunit);
Console.println(" with exception:"+e.getMessage());
//e.printStackTrace();
- Debug.abort()
+ System.exit(-1); //Debug.abort()
}
if (global.log()) {
global.log("internal pattern matching structure");
@@ -192,7 +321,7 @@ class TransMatch( global:scalac_Global )
return ts;
}
- override def transform( tree:Tree ):Tree = {
+ override def transform( tree: Tree ):Tree = {
if (tree == null)
return null;
else
diff --git a/sources/scala/tools/scalac/transformer/matching/PatternMatcher.scala b/sources/scala/tools/scalac/transformer/matching/PatternMatcher.scala
index 018053e148..6a739a55a1 100644
--- a/sources/scala/tools/scalac/transformer/matching/PatternMatcher.scala
+++ b/sources/scala/tools/scalac/transformer/matching/PatternMatcher.scala
@@ -107,6 +107,11 @@ class PatternMatcher(unit: CompilationUnit) extends PatternTool(unit) {
}
}
+ /** this method is only called if 2 patterns are redundant. In such
+ * a case, the right body has to be chosen by means of the guards!
+ * case 3 if false => "x";
+ * case 3 if true => "y";
+ */
protected def updateBody(tree: Body, bound: Array[ValDef], guard: Tree , body: Tree): Unit = {
if (tree.guard(tree.guard.length - 1) == Tree.Empty) {
//unit.error(body.pos, "unreachable code");
@@ -184,6 +189,7 @@ class PatternMatcher(unit: CompilationUnit) extends PatternTool(unit) {
env.newBoundVar( tree.symbol(), tree.getType(), header.selector);
node;
case Bind(name, pat) =>
+ //if ( tree.getType() == null ) throw new ApplicationError("Bind tpe is null"); // DEBUG
val node = patternNode(pat, header, env);
if ((env != null) && (tree.symbol() != defs.PATTERN_WILDCARD)) {
val casted = node.symbol();
@@ -261,18 +267,19 @@ class PatternMatcher(unit: CompilationUnit) extends PatternTool(unit) {
case Sequence(ts) =>
if ( !delegateSequenceMatching ) {
//throw new ApplicationError("cannot happen:"+tree);
+ //Console.println("PatternMatcher:patternNode:Sequence "+tree.getType());
mk.SequencePat(tree.pos, tree.getType(), ts.length);
} else {
mk.SeqContainerPat(tree.pos, tree.getType(), tree);
}
- case Alternative(ts) =>
- if(ts.length < 2)
+ case Alternative(branches) =>
+ if(branches.length < 2)
throw new ApplicationError("ill-formed Alternative");
val subroot = mk.ConstrPat(header.pos, header.getTpe());
subroot.and = mk.Header(header.pos, header.getTpe(), header.selector.duplicate());
val subenv = new CaseEnv(owner, unit);
- var i = 0; while(i < ts.length) {
- val target = enter1(ts(i), -1, subroot, subroot.symbol(), subenv);
+ var i = 0; while(i < branches.length) {
+ val target = enter1(branches(i), -1, subroot, subroot.symbol(), subenv);
target.and = mk.Body(tree.pos);
i = i + 1
}
@@ -289,6 +296,9 @@ class PatternMatcher(unit: CompilationUnit) extends PatternTool(unit) {
enter1(pat, index, target, newCasted, env);
case SequencePat(newCasted, len) =>
enter1(pat, index, target, newCasted, env);
+ /* Test
+ case AltPat() =>
+ */
case _ =>
enter1(pat, index, target, casted, env);
}
@@ -616,41 +626,52 @@ class PatternMatcher(unit: CompilationUnit) extends PatternTool(unit) {
var node = node1;
var res = gen.mkBooleanLit(node.pos, false);
+
while (node != null)
- node match {
- case _h:Header =>
- val selector = _h.selector;
- val next = _h.next;
- //res = cf.And(mkNegate(res), toTree(node.or, selector));
- //Console.println("HEADER TYPE = " + selector.type);
- if (optimize1(node.getTpe(), node.or))
- res = cf.Or(res, toOptTree(node.or, selector));
- else
- res = cf.Or(res, toTree(node.or, selector));
- node = next;
-
- case _b:Body =>
- var bound = _b.bound;
- val guard = _b.guard;
- val body = _b.body;
- if ((bound.length == 0) &&
- (guard.length == 0) &&
- (body.length == 0)) {
- return gen.mkBooleanLit(node.pos, true); // cf.Or(res, gen.mkBooleanLit(node.pos, true));
- } else if (!doBinding)
- bound = Predef.Array[Array[ValDef]]( Predef.Array[ValDef]() );
- var i = guard.length - 1; while(i >= 0) {
- val ts = bound(i).asInstanceOf[Array[Tree]];
- var res0 = gen.mkBlock(gen.Assign(gen.Ident(body(i).pos, resultVar),
- body(i)),
- gen.mkBooleanLit(body(i).pos, true));
- if (guard(i) != Tree.Empty)
- res0 = cf.And(guard(i), res0);
- res = cf.Or(gen.mkBlock(body(i).pos, ts, res0), res);
- i = i - 1
- }
- return res;
- }
+ node match {
+ case _h:Header =>
+ val selector = _h.selector;
+ val next = _h.next;
+ //res = cf.And(mkNegate(res), toTree(node.or, selector));
+ //Console.println("HEADER TYPE = " + selector.type);
+
+ /* TEST
+ next match {
+ case _b:Body if ((_b.guard.length > 1) ||
+ (_b.guard(0) != Tree.Empty)) =>
+ Console.println("guard! = "+_b.guard(0));
+ case _ =>
+ }
+ */
+
+ if (optimize1(node.getTpe(), node.or))
+ res = cf.Or(res, toOptTree(node.or, selector));
+ else
+ res = cf.Or(res, toTree(node.or, selector));
+ node = next;
+
+ case _b:Body =>
+ var bound = _b.bound;
+ val guard = _b.guard;
+ val body = _b.body;
+ if ((bound.length == 0) &&
+ (guard.length == 0) &&
+ (body.length == 0)) {
+ return gen.mkBooleanLit(node.pos, true); // cf.Or(res, gen.mkBooleanLit(node.pos, true));
+ } else if (!doBinding)
+ bound = Predef.Array[Array[ValDef]]( Predef.Array[ValDef]() );
+ var i = guard.length - 1; while(i >= 0) {
+ val ts = bound(i).asInstanceOf[Array[Tree]];
+ var res0 = gen.mkBlock(gen.Assign(gen.Ident(body(i).pos, resultVar),
+ body(i)),
+ gen.mkBooleanLit(body(i).pos, true));
+ if (guard(i) != Tree.Empty)
+ res0 = cf.And(guard(i), res0);
+ res = cf.Or(gen.mkBlock(body(i).pos, ts, res0), res);
+ i = i - 1
+ }
+ return res;
+ }
return res;
}
diff --git a/sources/scala/tools/scalac/transformer/matching/PatternNode.scala b/sources/scala/tools/scalac/transformer/matching/PatternNode.scala
index e081b8c099..28ac14d26c 100644
--- a/sources/scala/tools/scalac/transformer/matching/PatternNode.scala
+++ b/sources/scala/tools/scalac/transformer/matching/PatternNode.scala
@@ -147,6 +147,16 @@ package scala.tools.scalac.transformer.matching {
q match {
case ConstrPat(_) =>
q.getTpe().isSubType(this.getTpe());
+ /* TEST
+ case AltPat(subroot) =>
+ var node = subroot.and.or;
+ var res = false;
+ while(node!=null && !false) {
+ res = this subsumes(node);
+ node = node.or;
+ }
+ res
+ */
case _ =>
false;
}
@@ -174,6 +184,16 @@ package scala.tools.scalac.transformer.matching {
case _ =>
false;
}
+ /* TEST
+ case AltPat(subroot) =>
+ var node = subroot.and.or;
+ var res = false;
+ while(node!=null && !false) {
+ res = node subsumes q;
+ node = node.or;
+ }
+ res
+ */
case _ =>
false;
}
diff --git a/sources/scalac/ast/Transformer.java.tmpl b/sources/scalac/ast/Transformer.java.tmpl
index bf5fa09f4f..2fa347c305 100644
--- a/sources/scalac/ast/Transformer.java.tmpl
+++ b/sources/scalac/ast/Transformer.java.tmpl
@@ -205,12 +205,27 @@ public class GenTransformer {
case Block(Tree[] stats, Tree value):
return gen.Block(tree.pos, transform(stats), transform(value));
- // case Sequence(Tree[] trees):
+ case Sequence(Tree[] trees):
+ trees = transform(trees);
+ Tree seq = new Sequence(trees);
+ seq.pos = tree.pos;
+ seq.type = tree.type;
+ return seq;
// case Alternative(Tree[] trees):
- // case Bind(Name name, Tree rhs):
// case Visitor(CaseDef[] cases):
// case Function(ValDef[] vparams, Tree body):
+ case Bind(Name n, Tree pat): // test
+ Symbol sym = getSymbolFor(tree);
+ global.nextPhase();
+ sym.setType(tree.type);
+ global.prevPhase();
+ Tree bind = new ExtBind(sym, transform(pat));
+ bind.type = sym.getType();
+ bind.pos = tree.pos;
+ return bind;
+
+
case Assign(Tree lhs, Tree rhs):
return gen.Assign(tree.pos, transform(lhs), transform(rhs));
diff --git a/test/files/run/regularpatmat.check b/test/files/run/regularpatmat.check
index 7c6f67ea71..3417d9a98a 100644
--- a/test/files/run/regularpatmat.check
+++ b/test/files/run/regularpatmat.check
@@ -102,7 +102,10 @@ passed ok
passed ok
passed ok
passed ok
-testMZ - bugs #132 #133b #180 #195 #196
+testMZ - bugs #132 #133b #180 #195 #196 #398 #406 #441
+passed ok
+passed ok
+passed ok
passed ok
passed ok
passed ok
diff --git a/test/files/run/regularpatmat.scala b/test/files/run/regularpatmat.scala
index 6847861d4d..f6991cab5c 100644
--- a/test/files/run/regularpatmat.scala
+++ b/test/files/run/regularpatmat.scala
@@ -667,8 +667,41 @@ object testMZ {
case x::xs => "two"
}
+ def mat406() = {
+ class Type;
+ case class A() extends Type;
+ case class B() extends Type;
+ case class C() extends Type;
+
+ def foo(x: Type, y: Type): String = Pair(x, y) match {
+ case Pair(A(), A())
+ | Pair(A(), B())
+ | Pair(B(), A())
+ | Pair(B(), B()) => "3"
+ case Pair(C(), C()) => "4"
+ case Pair(A(), _)
+ | Pair(B(), _) => "7"
+ case _ => "8"
+ }
+
+ foo(A(), C())
+ }
+
+ def mat441() = {
+ val tata = 1;
+ val titi = 0.8 + Math.random();
+ try {
+ tata match {
+ case 1 if (titi < 0.5) => "a"
+ case 0 | 1 => "b"
+ }
+ } catch {
+ case _ => "c"
+ }
+ }
+
def main:Unit = {
- Console.println("testMZ - bugs #132 #133b #180 #195 #196");
+ Console.println("testMZ - bugs #132 #133b #180 #195 #196 #398 #406 #441");
assertEquals(testFoo( List(Two(),Two(),Two(),Two()) ),"b = Two");
assertEquals(testFoo( List(Two(),Two(),Two()) ),"a = Two");
assertEquals(testFoo( List(Two(),Two()) ),"a = Two");
@@ -687,7 +720,9 @@ object testMZ {
assertEquals(mat196( List(1) ),"default");
assertEquals(mat196( List() ),"case, b = List()");
assertEquals(mat398( List(2) ),"two");
-
+ assertEquals(mat398( List(2) ),"two");
+ assertEquals(mat406(), "7");
+ assertEquals(mat441(), "b");
()
}