diff options
author | buraq <buraq@epfl.ch> | 2005-06-10 16:37:26 +0000 |
---|---|---|
committer | buraq <buraq@epfl.ch> | 2005-06-10 16:37:26 +0000 |
commit | 20e20196473e16ace8e29ad8f85a9ec79af043aa (patch) | |
tree | ded50283cf48cca4e52a758f84c12009f1ec695d | |
parent | 6ad31934e9c09b5523b3d7304e4014ff1c3037df (diff) | |
download | scala-20e20196473e16ace8e29ad8f85a9ec79af043aa.tar.gz scala-20e20196473e16ace8e29ad8f85a9ec79af043aa.tar.bz2 scala-20e20196473e16ace8e29ad8f85a9ec79af043aa.zip |
fixed bugs #406 #440 #371
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"); () } |