From a61111367ae2b119157238a6817022b9654c498e Mon Sep 17 00:00:00 2001 From: "Emmanouil (Manos) Koukoutos" <emmanouil.koukoutos@epfl.ch> Date: Fri, 21 Nov 2014 16:59:16 +0100 Subject: [PATCH] Introduce LetPattern, LetTuple specializes it for TuplePatterns --- project/build.properties | 2 +- .../scala/leon/codegen/CodeGeneration.scala | 19 ---------- src/main/scala/leon/purescala/Common.scala | 10 ++++++ .../scala/leon/purescala/Constructors.scala | 7 +++- .../scala/leon/purescala/Extractors.scala | 30 +++++++++++++++- .../scala/leon/purescala/PrettyPrinter.scala | 36 +++++++++++-------- .../leon/purescala/ScopeSimplifier.scala | 14 +------- .../leon/purescala/TransformerWithPC.scala | 5 --- src/main/scala/leon/purescala/TreeOps.scala | 28 +++------------ src/main/scala/leon/purescala/Trees.scala | 9 ++--- .../scala/leon/purescala/TypeTreeOps.scala | 4 --- .../solvers/templates/TemplateGenerator.scala | 3 +- .../leon/solvers/z3/AbstractZ3Solver.scala | 26 ++++++++------ .../synthesis/utils/ExpressionGrammar.scala | 2 +- 14 files changed, 92 insertions(+), 103 deletions(-) diff --git a/project/build.properties b/project/build.properties index be6c454fb..748703f77 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.5 +sbt.version=0.13.7 diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala index ff969c68b..8a548ecdb 100644 --- a/src/main/scala/leon/codegen/CodeGeneration.scala +++ b/src/main/scala/leon/codegen/CodeGeneration.scala @@ -224,25 +224,6 @@ trait CodeGeneration { ch << instr mkExpr(b, ch)(locals.withVar(i -> slot)) - case LetTuple(is,d,b) => - mkExpr(d, ch) // the tuple - var count = 0 - val withSlots = is.map(i => (i, ch.getFreshVar)) - for((i,s) <- withSlots) { - ch << DUP - ch << Ldc(count) - ch << InvokeVirtual(TupleClass, "get", "(I)Ljava/lang/Object;") - mkUnbox(i.getType, ch) - val instr = i.getType match { - case Int32Type | CharType | BooleanType | UnitType => IStore(s) - case _ => AStore(s) - } - ch << instr - count += 1 - } - ch << POP - mkExpr(b, ch)(locals.withVars(withSlots.toMap)) - case IntLiteral(v) => ch << Ldc(v) diff --git a/src/main/scala/leon/purescala/Common.scala b/src/main/scala/leon/purescala/Common.scala index a34958333..626bfe4a4 100644 --- a/src/main/scala/leon/purescala/Common.scala +++ b/src/main/scala/leon/purescala/Common.scala @@ -91,4 +91,14 @@ object Common { } + def aliased(id1 : Identifier, id2 : Identifier) = { + id1.toString == id2.toString + } + + def aliased(ids1 : Set[Identifier], ids2 : Set[Identifier]) = { + val s1 = ids1.groupBy{ _.toString }.keySet + val s2 = ids2.groupBy{ _.toString }.keySet + !(s1 & s2).isEmpty + } + } diff --git a/src/main/scala/leon/purescala/Constructors.scala b/src/main/scala/leon/purescala/Constructors.scala index 9ec719e25..f81e359ef 100644 --- a/src/main/scala/leon/purescala/Constructors.scala +++ b/src/main/scala/leon/purescala/Constructors.scala @@ -30,7 +30,12 @@ object Constructors { Let(x, tupleSelect(value, 1), body) } case xs => - LetTuple(xs, value, body) + require( + value.getType.isInstanceOf[TupleType], + s"The definition value in LetTuple must be of some tuple type; yet we got [${value.getType}]. In expr: \n$this" + ) + + Extractors.LetPattern(TuplePattern(None,binders map { b => WildcardPattern(Some(b)) }), value, body) } def tupleChoose(ch: Choose): Expr = { diff --git a/src/main/scala/leon/purescala/Extractors.scala b/src/main/scala/leon/purescala/Extractors.scala index d8ba07c13..d329c6d3b 100644 --- a/src/main/scala/leon/purescala/Extractors.scala +++ b/src/main/scala/leon/purescala/Extractors.scala @@ -67,7 +67,6 @@ object Extractors { case MapIsDefinedAt(t1,t2) => Some((t1,t2, MapIsDefinedAt)) case ArraySelect(t1, t2) => Some((t1, t2, ArraySelect)) case Let(binders, e, body) => Some((e, body, (e: Expr, b: Expr) => Let(binders, e, b))) - case LetTuple(binders, e, body) => Some((e, body, (e: Expr, b: Expr) => LetTuple(binders, e, b))) case Require(pre, body) => Some((pre, body, Require)) case Ensuring(body, id, post) => Some((body, post, (b: Expr, p: Expr) => Ensuring(b, id, p))) case Assert(const, oerr, body) => Some((const, body, (c: Expr, b: Expr) => Assert(c, oerr, b))) @@ -304,4 +303,33 @@ object Extractors { case other => Seq(other) } } + + object LetPattern { + def apply(patt : Pattern, value: Expr, body: Expr) : Expr = { + patt match { + case WildcardPattern(Some(binder)) => Let(binder, value, body) + case _ => MatchExpr(value, List(SimpleCase(patt, body))) + } + } + + def unapply(me : MatchExpr) : Option[(Pattern, Expr, Expr)] = { + if (me eq null) None else { me match { + case MatchExpr(scrut, List(SimpleCase(pattern, body))) if !aliased(pattern.binders, variablesOf(scrut)) => + Some(( pattern, scrut, body )) + case _ => None + }} + } + } + + object LetTuple { + def unapply(me : MatchExpr) : Option[(Seq[Identifier], Expr, Expr)] = { + if (me eq null) None else { me match { + case LetPattern(TuplePattern(None,subPatts), value, body) if + subPatts forall { case WildcardPattern(Some(_)) => true; case _ => false } => + Some((subPatts map { _.binder.get }, value, body )) + case _ => None + }} + } + } + } diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala index 43d98b758..8127e0af6 100644 --- a/src/main/scala/leon/purescala/PrettyPrinter.scala +++ b/src/main/scala/leon/purescala/PrettyPrinter.scala @@ -13,8 +13,9 @@ import utils._ import java.lang.StringBuffer import PrinterHelpers._ -import TreeOps.{isStringLiteral, isListLiteral, simplestValue} +import TreeOps.{isStringLiteral, isListLiteral, simplestValue, variablesOf} import TypeTreeOps.leastUpperBound +import Extractors.LetPattern import synthesis.Witnesses._ @@ -174,20 +175,9 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe case Variable(id) => p"$id" - case LetTuple(bs,d,e) => - optB { e match { - case _:LetDef | _ : Let | _ : LetTuple => - p"""|val ($bs) = { - | $d - |} - |$e""" - case _ => - p"""|val ($bs) = $d; - |$e""" - }} case Let(b,d,e) => optB { e match { - case _:LetDef | _ : Let | _ : LetTuple => + case _:LetDef | _ : Let | LetPattern(_,_,_) => p"""|val $b = { | $d |} @@ -436,6 +426,22 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe |}""" } + case LetPattern(p,s,rhs) => + rhs match { + case _:LetDef | _ : Let | LetPattern(_,_,_) => + optP { + p"""|val $p = { + | $s + |} + |$rhs""" + } + + case _ => + optP { + p"""|val $p = $s + |$rhs""" + } + } case MatchExpr(s, csc) => optP { @@ -680,7 +686,7 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe case (_: Require, _) => true case (_: Assert, Some(_: Definition)) => true case (_, Some(_: Definition)) => false - case (_, Some(_: MatchExpr | _: MatchCase | _: Let | _: LetTuple | _: LetDef )) => false + case (_, Some(_: MatchExpr | _: MatchCase | _: Let | _: LetDef )) => false case (_, _) => true } @@ -703,7 +709,7 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe case (_, Some(_: Assert)) => false case (_, Some(_: Require)) => false case (_, Some(_: Definition)) => false - case (_, Some(_: MatchExpr | _: MatchCase | _: Let | _: LetTuple | _: LetDef | _: IfExpr | _ : CaseClass)) => false + case (_, Some(_: MatchExpr | _: MatchCase | _: Let | _: LetDef | _: IfExpr | _ : CaseClass)) => false case (b1 @ BinaryMethodCall(_, _, _), Some(b2 @ BinaryMethodCall(_, _, _))) if precedence(b1) > precedence(b2) => false case (BinaryMethodCall(_, _, _), Some(_: FunctionInvocation)) => true case (_, Some(_: FunctionInvocation)) => false diff --git a/src/main/scala/leon/purescala/ScopeSimplifier.scala b/src/main/scala/leon/purescala/ScopeSimplifier.scala index 97ba8a1fe..fed50fe43 100644 --- a/src/main/scala/leon/purescala/ScopeSimplifier.scala +++ b/src/main/scala/leon/purescala/ScopeSimplifier.scala @@ -62,19 +62,7 @@ class ScopeSimplifier extends Transformer { } LetDef(newFd, rec(body, newScope)) - - case LetTuple(is, e, b) => - var newScope = scope - val sis = for (i <- is) yield { - val si = genId(i, newScope) - newScope = newScope.register(i -> si) - si - } - - val se = rec(e, scope) - val sb = rec(b, newScope) - LetTuple(sis, se, sb) - + case MatchExpr(scrut, cases) => val rs = rec(scrut, scope) diff --git a/src/main/scala/leon/purescala/TransformerWithPC.scala b/src/main/scala/leon/purescala/TransformerWithPC.scala index a3437b69c..10cc17dfe 100644 --- a/src/main/scala/leon/purescala/TransformerWithPC.scala +++ b/src/main/scala/leon/purescala/TransformerWithPC.scala @@ -42,11 +42,6 @@ abstract class TransformerWithPC extends Transformer { }).copiedFrom(e) - case LetTuple(is, e, b) => - val se = rec(e, path) - val sb = rec(b, register(Equals(Tuple(is.map(Variable(_))), se), path)) - LetTuple(is, se, sb).copiedFrom(e) - case IfExpr(cond, thenn, elze) => val rc = rec(cond, path) diff --git a/src/main/scala/leon/purescala/TreeOps.scala b/src/main/scala/leon/purescala/TreeOps.scala index 2789fb43a..a0313c5dc 100644 --- a/src/main/scala/leon/purescala/TreeOps.scala +++ b/src/main/scala/leon/purescala/TreeOps.scala @@ -447,11 +447,6 @@ object TreeOps { val newID = FreshIdentifier(i.name, true).copiedFrom(i) Some(Let(newID, e, replace(Map(Variable(i) -> Variable(newID)), b))) - case lt @ LetTuple(ids,e,b) => - val newIDs = ids.map(_.freshen) - val substsMap: Map[Expr, Expr] = (ids zip newIDs).map { case (id, newId) => (id.toVariable -> newId.toVariable) }.toMap - Some(LetTuple(newIDs, e, replace(substsMap, b))) - case _ => None })(expr) } @@ -482,7 +477,7 @@ object TreeOps { Some(Let(id, v, tupleSelect(b, ts))) case TupleSelect(LetTuple(ids, v, b), ts) => - Some(LetTuple(ids, v, tupleSelect(b, ts))) + Some(letTuple(ids, v, tupleSelect(b, ts))) case IfExpr(c, thenn, elze) if (thenn == elze) && isDeterministic(e) => Some(thenn) @@ -578,15 +573,8 @@ object TreeOps { true } }.unzip - - - if (remIds.isEmpty) { - Some(newBody) - } else if (remIds.tail.isEmpty) { - Some(Let(remIds.head, remExprs.head, newBody)) - } else { - Some(LetTuple(remIds, Tuple(remExprs), newBody)) - } + + Some(Constructors.letTuple(remIds, tupleWrap(remExprs), newBody)) case l @ LetTuple(ids, tExpr: Terminal, body) if isDeterministic(body) => val substMap : Map[Expr,Expr] = ids.map(Variable(_) : Expr).zipWithIndex.toMap.map { @@ -1659,14 +1647,6 @@ object TreeOps { isHomo(v1, v2) && isHomo(e1, e2)(map + (id1 -> id2)) - case (LetTuple(ids1, v1, e1), LetTuple(ids2, v2, e2)) => - if (ids1.size == ids2.size) { - isHomo(v1, v2) && - isHomo(e1, e2)(map ++ (ids1 zip ids2)) - } else { - false - } - case (LetDef(fd1, e1), LetDef(fd2, e2)) => fdHomo(fd1, fd2) && isHomo(e1, e2)(map + (fd1.id -> fd2.id)) @@ -2015,7 +1995,7 @@ object TreeOps { case Let(i, e, b) => Let(i, e, apply(b, args)) case LetTuple(is, es, b) => - LetTuple(is, es, apply(b, args)) + letTuple(is, es, apply(b, args)) case Lambda(params, body) => replaceFromIDs((params.map(_.id) zip args).toMap, body) case _ => Application(expr, args) diff --git a/src/main/scala/leon/purescala/Trees.scala b/src/main/scala/leon/purescala/Trees.scala index 89a23828b..e8999b26b 100644 --- a/src/main/scala/leon/purescala/Trees.scala +++ b/src/main/scala/leon/purescala/Trees.scala @@ -8,6 +8,7 @@ import utils._ /** AST definitions for Pure Scala. */ object Trees { import Common._ + import TreeOps.variablesOf import TypeTrees._ import TypeTreeOps._ import Definitions._ @@ -55,17 +56,11 @@ object Trees { } } + /* Like vals */ case class Let(binder: Identifier, value: Expr, body: Expr) extends Expr { def getType = body.getType } - case class LetTuple(binders: Seq[Identifier], value: Expr, body: Expr) extends Expr { - require(value.getType.isInstanceOf[TupleType], - "The definition value in LetTuple must be of some tuple type; yet we got [%s]. In expr: \n%s".format(value.getType, this)) - - def getType = body.getType - } - case class LetDef(fd: FunDef, body: Expr) extends Expr { def getType = body.getType } diff --git a/src/main/scala/leon/purescala/TypeTreeOps.scala b/src/main/scala/leon/purescala/TypeTreeOps.scala index 46f8be837..518d19370 100644 --- a/src/main/scala/leon/purescala/TypeTreeOps.scala +++ b/src/main/scala/leon/purescala/TypeTreeOps.scala @@ -279,10 +279,6 @@ object TypeTreeOps { val newId = freshId(id, tpeSub(id.getType)) Let(newId, srec(value), rec(idsMap + (id -> newId))(body)).copiedFrom(l) - case l @ LetTuple(ids, value, body) => - val newIds = ids.map(id => freshId(id, tpeSub(id.getType))) - LetTuple(newIds, srec(value), rec(idsMap ++ (ids zip newIds))(body)).copiedFrom(l) - case c @ Choose(xs, pred, oimpl) => val newXs = xs.map(id => freshId(id, tpeSub(id.getType))) Choose(newXs, rec(idsMap ++ (xs zip newXs))(pred), oimpl.map(srec)).copiedFrom(c) diff --git a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala index a570d9597..436220efa 100644 --- a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala +++ b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala @@ -206,6 +206,7 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T]) { val rb = rec(pathVar, replace(Map(Variable(i) -> Variable(newExpr)), b)) rb + /* TODO: maybe we want this specialization? case l @ LetTuple(is, e, b) => val tuple : Identifier = FreshIdentifier("t", true).setType(TupleType(is.map(_.getType))) storeExpr(tuple) @@ -222,7 +223,7 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T]) { val rb = rec(pathVar, replace(mapping.toMap, b)) rb - + */ case m : MatchExpr => sys.error("'MatchExpr's should have been eliminated before generating templates.") case p : Passes => sys.error("'Passes's should have been eliminated before generating templates.") case g : Gives => sys.error("'Gives' should have been eliminated before generating templates.") diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala index 03201a3eb..0b599a022 100644 --- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala @@ -10,6 +10,7 @@ import solvers._ import purescala.Common._ import purescala.Definitions._ import purescala.Constructors._ +import purescala.Extractors.LetTuple import purescala.Trees._ import purescala.TypeTreeOps._ import xlang.Trees._ @@ -495,6 +496,20 @@ trait AbstractZ3Solver } def rec(ex: Expr): Z3AST = ex match { + + // TODO: Leave that as a specialization? + case LetTuple(ids, e, b) => { + var ix = 1 + z3Vars = z3Vars ++ ids.map((id) => { + val entry = (id -> rec(tupleSelect(e, ix))) + ix += 1 + entry + }) + val rb = rec(b) + z3Vars = z3Vars -- ids + rb + } + case p @ Passes(_, _, _) => rec(p.asConstraint) @@ -524,17 +539,6 @@ trait AbstractZ3Solver rb } - case LetTuple(ids, e, b) => { - var ix = 1 - z3Vars = z3Vars ++ ids.map((id) => { - val entry = (id -> rec(tupleSelect(e, ix))) - ix += 1 - entry - }) - val rb = rec(b) - z3Vars = z3Vars -- ids - rb - } case Waypoint(_, e) => rec(e) case e @ Error(tpe, _) => { val newAST = z3.mkFreshConst("errorValue", typeToSort(tpe)) diff --git a/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala b/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala index 2c8be3cb2..97687c425 100644 --- a/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala +++ b/src/main/scala/leon/synthesis/utils/ExpressionGrammar.scala @@ -282,7 +282,7 @@ object ExpressionGrammars { val subs: Seq[(L, Gen)] = (e match { - case _: Terminal | _: Let | _: LetTuple | _: LetDef | _: MatchExpr => + case _: Terminal | _: Let | _: LetDef | _: MatchExpr => gens(e, gl, Nil, { _ => e }) ++ cegis(gl) case cc @ CaseClass(cct, exprs) => -- GitLab