diff --git a/src/it/scala/inox/TestSilentReporter.scala b/src/it/scala/inox/TestSilentReporter.scala index 96deee1c47d6b20025c24707fffc9c3e15c73b37..6cb2bd95f5ddb21ee42a18cf05085269b1d66449 100644 --- a/src/it/scala/inox/TestSilentReporter.scala +++ b/src/it/scala/inox/TestSilentReporter.scala @@ -13,6 +13,7 @@ class TestSilentReporter extends DefaultReporter(Set()) { override def debug(pos: utils.Position, msg: => Any)(implicit section: DebugSection): Unit = { //println(msg) + super.debug(pos, msg) } } diff --git a/src/it/scala/inox/solvers/unrolling/FunctionEqualitySuite.scala b/src/it/scala/inox/solvers/unrolling/FunctionEqualitySuite.scala new file mode 100644 index 0000000000000000000000000000000000000000..ad8c11268ba74b1cb249ceca3fc171a33cb83866 --- /dev/null +++ b/src/it/scala/inox/solvers/unrolling/FunctionEqualitySuite.scala @@ -0,0 +1,50 @@ +/* Copyright 2009-2016 EPFL, Lausanne */ + +package inox +package solvers +package unrolling + +class FunctionEqualitySuite extends SolvingTestSuite { + import inox.trees._ + import dsl._ + + val v = FreshIdentifier("value") + + val optionID = FreshIdentifier("Option") + val someID = FreshIdentifier("Some") + val noneID = FreshIdentifier("None") + + val option = mkSort(optionID)("A")(Seq(someID, noneID)) + val none = mkConstructor(noneID)("A")(Some(optionID))(_ => Seq.empty) + val some = mkConstructor(someID)("A")(Some(optionID)) { + case Seq(aT) => Seq(ValDef(v, aT)) + } + + val f = FreshIdentifier("f") + val mmapID = FreshIdentifier("MMap") + val mmap = mkConstructor(mmapID)("A","B")(None) { + case Seq(aT, bT) => Seq(ValDef(f, aT =>: T(optionID)(bT))) + } + + val containsID = FreshIdentifier("contains") + val contains = mkFunDef(containsID)("A", "B") { case Seq(aT, bT) => ( + Seq("m" :: T(mmapID)(aT, bT), "k" :: aT), BooleanType, { case Seq(m, k) => + m.getField(f)(k).isInstOf(T(someID)(bT)) + }) + } + + val symbols = new Symbols( + Map(containsID -> contains), + Map(optionID -> option, someID -> some, noneID -> none, mmapID -> mmap) + ) + + test("simple theorem") { ctx => + val program = InoxProgram(ctx, symbols) + val clause = let( + "states" :: T(mmapID)(IntegerType, IntegerType =>: IntegerType), + T(mmapID)(IntegerType, IntegerType =>: IntegerType)(\("i" :: IntegerType)(i => T(someID)(IntegerType =>: IntegerType)(\("x" :: IntegerType)(x => IntegerLiteral(0))))) + )(states => contains(IntegerType, IntegerType =>: IntegerType)(states, IntegerLiteral(0)) && E(false)) + + assert(SimpleSolverAPI(SolverFactory.default(program)).solveSAT(Not(clause)).isSAT) + } +} diff --git a/src/main/scala/inox/ast/Definitions.scala b/src/main/scala/inox/ast/Definitions.scala index e54a768cc37b513f1d03806f9c55071064781795..cac42a3e01e79aa6b9efbd8bc42632d94d355638 100644 --- a/src/main/scala/inox/ast/Definitions.scala +++ b/src/main/scala/inox/ast/Definitions.scala @@ -131,9 +131,9 @@ trait Definitions { self: Trees => override def toString: String = asString(PrinterOptions.fromSymbols(this, InoxContext.printNames)) override def asString(implicit opts: PrinterOptions): String = { - adts.map(p => PrettyPrinter(p._2, opts)).mkString("\n\n") + + adts.map(p => prettyPrint(p._2, opts)).mkString("\n\n") + "\n\n-----------\n\n" + - functions.map(p => PrettyPrinter(p._2, opts)).mkString("\n\n") + functions.map(p => prettyPrint(p._2, opts)).mkString("\n\n") } def transform(t: TreeTransformer): Symbols = NoSymbols.withFunctions { diff --git a/src/main/scala/inox/ast/Printers.scala b/src/main/scala/inox/ast/Printers.scala index fecbe01df372c03eee42972cdd1cdcf63aa16cdf..cde78421cb5803350e2ac03ca70cec2f73ecda95 100644 --- a/src/main/scala/inox/ast/Printers.scala +++ b/src/main/scala/inox/ast/Printers.scala @@ -17,7 +17,8 @@ trait Printers { case class PrinterContext(current: Tree, parents: List[Tree], lvl: Int, - printer: PrettyPrinter) { + opts: PrinterOptions, + sb: StringBuffer = new StringBuffer) { def parent = parents.headOption } @@ -61,348 +62,357 @@ trait Printers { val sb: StringBuffer = new StringBuffer) { override def toString = sb.toString + } - protected def optP(body: => Any)(implicit ctx: PrinterContext) = { - if (requiresParentheses(ctx.current, ctx.parent)) { - sb.append("(") - body - sb.append(")") - } else { - body - } + protected def optP(body: => Any)(implicit ctx: PrinterContext) = { + if (requiresParentheses(ctx.current, ctx.parent)) { + ctx.sb.append("(") + body + ctx.sb.append(")") + } else { + body } + } - private val dbquote = "\"" + private val dbquote = "\"" - def pp(tree: Tree)(implicit ctx: PrinterContext): Unit = { + def pp(tree: Tree)(implicit ctx: PrinterContext): Unit = { + ppPrefix(tree) + ppBody(tree) + ppSuffix(tree) + } - if (requiresBraces(tree, ctx.parent) && !ctx.parent.contains(tree)) { - p"""|{ - | $tree - |}""" - return - } + protected def ppPrefix(tree: Tree)(implicit ctx: PrinterContext): Unit = { + if (requiresBraces(tree, ctx.parent) && !ctx.parent.contains(tree)) { + p"""|{ + | $tree + |}""" + return + } - if (opts.printTypes) { - tree match { - case t: Expr => - p"⟨" + if (ctx.opts.printTypes) { + tree match { + case t: Expr => + p"⟨" - case _ => - } + case _ => } - tree match { - case Variable(id, _) => - p"$id" + } + } - case Let(vd, expr, SubString(v2: Variable, start, StringLength(v3: Variable))) if vd.toVariable == v2 && v2 == v3 => - p"$expr.substring($start)" + protected def ppBody(tree: Tree)(implicit ctx: PrinterContext): Unit = tree match { + case Variable(id, _) => + p"$id" - case Let(b, d, e) => - p"""|val $b = $d - |$e""" + case Let(vd, expr, SubString(v2: Variable, start, StringLength(v3: Variable))) if vd.toVariable == v2 && v2 == v3 => + p"$expr.substring($start)" - case Forall(args, e) => - p"\u2200${nary(args)}. $e" + case Let(b, d, e) => + p"""|val $b = $d + |$e""" - case Choose(res, pred) => - p"choose(($res) => $pred)" + case Forall(args, e) => + p"\u2200${nary(args)}. $e" - case e @ ADT(adt, args) => - p"$adt($args)" + case Choose(res, pred) => + p"choose(($res) => $pred)" - case And(exprs) => optP { - p"${nary(exprs, " && ")}" - } - case Or(exprs) => optP { - p"${nary(exprs, "| || ")}" - } // Ugliness award! The first | is there to shield from stripMargin() - case Not(Equals(l, r)) => optP { - p"$l \u2260 $r" - } - case Implies(l, r) => optP { - p"$l ==> $r" - } - case UMinus(expr) => p"-$expr" - case Equals(l, r) => optP { - p"$l == $r" - } + case e @ ADT(adt, args) => + p"$adt($args)" - case StringConcat(lhs, rhs) => optP { - p"$lhs + $rhs" - } - case SubString(expr, start, end) => p"$expr.substring($start, $end)" - case StringLength(expr) => p"$expr.length" - - case IntLiteral(v) => p"$v" - case BVLiteral(bits, size) => p"x${(size to 1 by -1).map(i => if (bits(i)) "1" else "0")}" - case IntegerLiteral(v) => p"$v" - case FractionLiteral(n, d) => - if (d == 1) p"$n" - else p"$n/$d" - case CharLiteral(v) => p"$v" - case BooleanLiteral(v) => p"$v" - case UnitLiteral() => p"()" - case StringLiteral(v) => - if (v.count(c => c == '\n') >= 1 && v.length >= 80 && v.indexOf("\"\"\"") == -1) { - p"$dbquote$dbquote$dbquote$v$dbquote$dbquote$dbquote" - } else { - val escaped = StringEscapeUtils.escapeJava(v) - p"$dbquote$escaped$dbquote" - } - case GenericValue(tp, id) => p"$tp#$id" - case Tuple(exprs) => p"($exprs)" - case TupleSelect(t, i) => p"$t._$i" - case AsInstanceOf(e, ct) => p"""$e.asInstanceOf[$ct]""" - case IsInstanceOf(e, cct) => p"$e.isInstanceOf[$cct]" - case ADTSelector(e, id) => p"$e.$id" - - case FunctionInvocation(id, tps, args) => - p"$id${nary(tps, ", ", "[", "]")}" - if (args.nonEmpty) { - p"($args)" - } + case And(exprs) => optP { + p"${nary(exprs, " && ")}" + } + case Or(exprs) => optP { + p"${nary(exprs, "| || ")}" + } // Ugliness award! The first | is there to shield from stripMargin() + case Not(Equals(l, r)) => optP { + p"$l \u2260 $r" + } + case Implies(l, r) => optP { + p"$l ==> $r" + } + case UMinus(expr) => p"-$expr" + case Equals(l, r) => optP { + p"$l == $r" + } - case Application(caller, args) => - p"$caller($args)" + case StringConcat(lhs, rhs) => optP { + p"$lhs + $rhs" + } + case SubString(expr, start, end) => p"$expr.substring($start, $end)" + case StringLength(expr) => p"$expr.length" + + case IntLiteral(v) => p"$v" + case BVLiteral(bits, size) => p"x${(size to 1 by -1).map(i => if (bits(i)) "1" else "0")}" + case IntegerLiteral(v) => p"$v" + case FractionLiteral(n, d) => + if (d == 1) p"$n" + else p"$n/$d" + case CharLiteral(v) => p"$v" + case BooleanLiteral(v) => p"$v" + case UnitLiteral() => p"()" + case StringLiteral(v) => + if (v.count(c => c == '\n') >= 1 && v.length >= 80 && v.indexOf("\"\"\"") == -1) { + p"$dbquote$dbquote$dbquote$v$dbquote$dbquote$dbquote" + } else { + val escaped = StringEscapeUtils.escapeJava(v) + p"$dbquote$escaped$dbquote" + } + case GenericValue(tp, id) => p"$tp#$id" + case Tuple(exprs) => p"($exprs)" + case TupleSelect(t, i) => p"$t._$i" + case AsInstanceOf(e, ct) => p"""$e.asInstanceOf[$ct]""" + case IsInstanceOf(e, cct) => p"$e.isInstanceOf[$cct]" + case ADTSelector(e, id) => p"$e.$id" + + case FunctionInvocation(id, tps, args) => + p"$id${nary(tps, ", ", "[", "]")}" + if (args.nonEmpty) { + p"($args)" + } - case Lambda(Seq(vd), FunctionInvocation(id, Seq(), Seq(arg))) if vd.toVariable == arg => - p"$id" + case Application(caller, args) => + p"$caller($args)" - case Lambda(args, body) => - optP { - p"($args) => $body" - } + case Lambda(Seq(vd), FunctionInvocation(id, Seq(), Seq(arg))) if vd.toVariable == arg => + p"$id" - case Plus(l, r) => optP { - p"$l + $r" - } - case Minus(l, r) => optP { - p"$l - $r" - } - case Times(l, r) => optP { - p"$l * $r" - } - case Division(l, r) => optP { - p"$l / $r" - } - case Remainder(l, r) => optP { - p"$l % $r" - } - case Modulo(l, r) => optP { - p"$l mod $r" - } - case LessThan(l, r) => optP { - p"$l < $r" - } - case GreaterThan(l, r) => optP { - p"$l > $r" - } - case LessEquals(l, r) => optP { - p"$l <= $r" - } - case GreaterEquals(l, r) => optP { - p"$l >= $r" - } - case BVNot(e) => optP { - p"~$e" - } - case BVXor(l, r) => optP { - p"$l ^ $r" - } - case BVOr(l, r) => optP { - p"$l | $r" - } - case BVAnd(l, r) => optP { - p"$l & $r" - } - case BVShiftLeft(l, r) => optP { - p"$l << $r" - } - case BVAShiftRight(l, r) => optP { - p"$l >> $r" - } - case BVLShiftRight(l, r) => optP { - p"$l >>> $r" - } - case fs@FiniteSet(rs, _) => p"{${rs.distinct}}" - case fs@FiniteBag(rs, _) => p"{${rs.toMap.toSeq}}" - case fm@FiniteMap(rs, _, _) => p"{${rs.toMap.toSeq}}" - case Not(ElementOfSet(e, s)) => p"$e \u2209 $s" - case ElementOfSet(e, s) => p"$e \u2208 $s" - case SubsetOf(l, r) => p"$l \u2286 $r" - case Not(SubsetOf(l, r)) => p"$l \u2288 $r" - case SetAdd(s, e) => p"$s \u222A {$e}" - case SetUnion(l, r) => p"$l \u222A $r" - case BagUnion(l, r) => p"$l \u222A $r" - case SetDifference(l, r) => p"$l \\ $r" - case BagDifference(l, r) => p"$l \\ $r" - case SetIntersection(l, r) => p"$l \u2229 $r" - case BagIntersection(l, r) => p"$l \u2229 $r" - case BagAdd(b, e) => p"$b + $e" - case MultiplicityInBag(e, b) => p"$b($e)" - case MapApply(m, k) => p"$m($k)" - - case Not(expr) => p"\u00AC$expr" - - case vd@ValDef(id, tpe) => - p"$id : $tpe" - - case (tfd: TypedFunDef) => p"typed def ${tfd.id}[${tfd.tps}]" - case TypeParameterDef(tp) => p"$tp" - case TypeParameter(id) => p"$id" - - - case IfExpr(c, t, ie: IfExpr) => - optP { - p"""|if ($c) { - | $t - |} else $ie""" - } + case Lambda(args, body) => + optP { + p"($args) => $body" + } - case IfExpr(c, t, e) => - optP { - p"""|if ($c) { - | $t - |} else { - | $e - |}""" - } + case Plus(l, r) => optP { + p"$l + $r" + } + case Minus(l, r) => optP { + p"$l - $r" + } + case Times(l, r) => optP { + p"$l * $r" + } + case Division(l, r) => optP { + p"$l / $r" + } + case Remainder(l, r) => optP { + p"$l % $r" + } + case Modulo(l, r) => optP { + p"$l mod $r" + } + case LessThan(l, r) => optP { + p"$l < $r" + } + case GreaterThan(l, r) => optP { + p"$l > $r" + } + case LessEquals(l, r) => optP { + p"$l <= $r" + } + case GreaterEquals(l, r) => optP { + p"$l >= $r" + } + case BVNot(e) => optP { + p"~$e" + } + case BVXor(l, r) => optP { + p"$l ^ $r" + } + case BVOr(l, r) => optP { + p"$l | $r" + } + case BVAnd(l, r) => optP { + p"$l & $r" + } + case BVShiftLeft(l, r) => optP { + p"$l << $r" + } + case BVAShiftRight(l, r) => optP { + p"$l >> $r" + } + case BVLShiftRight(l, r) => optP { + p"$l >>> $r" + } + case fs@FiniteSet(rs, _) => p"{${rs.distinct}}" + case fs@FiniteBag(rs, _) => p"{${rs.toMap.toSeq}}" + case fm@FiniteMap(rs, _, _) => p"{${rs.toMap.toSeq}}" + case Not(ElementOfSet(e, s)) => p"$e \u2209 $s" + case ElementOfSet(e, s) => p"$e \u2208 $s" + case SubsetOf(l, r) => p"$l \u2286 $r" + case Not(SubsetOf(l, r)) => p"$l \u2288 $r" + case SetAdd(s, e) => p"$s \u222A {$e}" + case SetUnion(l, r) => p"$l \u222A $r" + case BagUnion(l, r) => p"$l \u222A $r" + case SetDifference(l, r) => p"$l \\ $r" + case BagDifference(l, r) => p"$l \\ $r" + case SetIntersection(l, r) => p"$l \u2229 $r" + case BagIntersection(l, r) => p"$l \u2229 $r" + case BagAdd(b, e) => p"$b + $e" + case MultiplicityInBag(e, b) => p"$b($e)" + case MapApply(m, k) => p"$m($k)" + + case Not(expr) => p"\u00AC$expr" + + case vd@ValDef(id, tpe) => + p"$id : $tpe" + + case (tfd: TypedFunDef) => p"typed def ${tfd.id}[${tfd.tps}]" + case TypeParameterDef(tp) => p"$tp" + case TypeParameter(id) => p"$id" + + + case IfExpr(c, t, ie: IfExpr) => + optP { + p"""|if ($c) { + | $t + |} else $ie""" + } - // Types - case Untyped => p"<untyped>" - case UnitType => p"Unit" - case Int32Type => p"Int" - case IntegerType => p"BigInt" - case RealType => p"Real" - case CharType => p"Char" - case BooleanType => p"Boolean" - case StringType => p"String" - case SetType(bt) => p"Set[$bt]" - case BagType(bt) => p"Bag[$bt]" - case MapType(ft, tt) => p"Map[$ft, $tt]" - case TupleType(tpes) => p"($tpes)" - case FunctionType(fts, tt) => p"($fts) => $tt" - case adt: ADTType => - p"${adt.id}${nary(adt.tps, ", ", "[", "]")}" - - // Definitions - case sort: ADTSort => - p"abstract class ${sort.id}${nary(sort.tparams, ", ", "[", "]")}" - - case cons: ADTConstructor => - p"case class ${cons.id}" - p"${nary(cons.tparams, ", ", "[", "]")}" - p"(${cons.fields})" - - cons.sort.foreach { s => - // Remember child and parents tparams are simple bijection - p" extends $s${nary(cons.tparams, ", ", "[", "]")}" - } + case IfExpr(c, t, e) => + optP { + p"""|if ($c) { + | $t + |} else { + | $e + |}""" + } - case fd: FunDef => - for (an <- fd.flags) { - p"""|@$an - |""" - } + // Types + case Untyped => p"<untyped>" + case UnitType => p"Unit" + case Int32Type => p"Int" + case IntegerType => p"BigInt" + case RealType => p"Real" + case CharType => p"Char" + case BooleanType => p"Boolean" + case StringType => p"String" + case SetType(bt) => p"Set[$bt]" + case BagType(bt) => p"Bag[$bt]" + case MapType(ft, tt) => p"Map[$ft, $tt]" + case TupleType(tpes) => p"($tpes)" + case FunctionType(fts, tt) => p"($fts) => $tt" + case adt: ADTType => + p"${adt.id}${nary(adt.tps, ", ", "[", "]")}" + + // Definitions + case sort: ADTSort => + p"abstract class ${sort.id}${nary(sort.tparams, ", ", "[", "]")}" + + case cons: ADTConstructor => + p"case class ${cons.id}" + p"${nary(cons.tparams, ", ", "[", "]")}" + p"(${cons.fields})" + + cons.sort.foreach { s => + // Remember child and parents tparams are simple bijection + p" extends $s${nary(cons.tparams, ", ", "[", "]")}" + } - p"def ${fd.id}${nary(fd.tparams, ", ", "[", "]")}" - if (fd.params.nonEmpty) { - p"(${fd.params}): " - } + case fd: FunDef => + for (an <- fd.flags) { + p"""|@$an + |""" + } - p"${fd.returnType} = " - p"${fd.fullBody}" + p"def ${fd.id}${nary(fd.tparams, ", ", "[", "]")}" + if (fd.params.nonEmpty) { + p"(${fd.params}): " + } - case (tree: PrettyPrintable) => tree.printWith(ctx) + p"${fd.returnType} = " + p"${fd.fullBody}" - case _ => sb.append("Tree? (" + tree.getClass + ")") - } - if (opts.printTypes) { - tree match { - case t: Expr => - p" : ${t.getType(opts.symbols.get)} ⟩" + case (tree: PrettyPrintable) => tree.printWith(ctx) - case _ => - } + case _ => ctx.sb.append("Tree? (" + tree.getClass + ")") + } + + protected def ppSuffix(tree: Tree)(implicit ctx: PrinterContext): Unit = { + if (ctx.opts.printTypes) { + tree match { + case t: Expr => + p" : ${t.getType(ctx.opts.symbols.get)} ⟩" + + case _ => } - if (opts.printPositions) { - tree.getPos match { - case op: OffsetPosition => - p"@($op)" - case rp: RangePosition => - if (rp.lineFrom == rp.lineTo) { - if (rp.colFrom == rp.colTo) { - p"@(${rp.lineFrom}:${rp.colFrom})" - } else { - p"@(${rp.lineFrom}:${rp.colFrom}-${rp.colTo})" - } + } + if (ctx.opts.printPositions) { + tree.getPos match { + case op: OffsetPosition => + p"@($op)" + case rp: RangePosition => + if (rp.lineFrom == rp.lineTo) { + if (rp.colFrom == rp.colTo) { + p"@(${rp.lineFrom}:${rp.colFrom})" } else { - p"@(${rp.focusBegin}-${rp.focusEnd})" + p"@(${rp.lineFrom}:${rp.colFrom}-${rp.colTo})" } - case _ => - p"@(?)" - } + } else { + p"@(${rp.focusBegin}-${rp.focusEnd})" + } + case _ => + p"@(?)" } } + } - protected def isSimpleExpr(e: Expr): Boolean = e match { - case _: Let => false - case p: PrettyPrintable => p.isSimpleExpr - case _ => true - } + protected def isSimpleExpr(e: Expr): Boolean = e match { + case _: Let => false + case p: PrettyPrintable => p.isSimpleExpr + case _ => true + } - protected def noBracesSub(e: Expr): Seq[Expr] = e match { - case Let(_, _, bd) => Seq(bd) - case IfExpr(_, t, e) => Seq(t, e) // if-else always has braces anyway - case _ => Seq() - } + protected def noBracesSub(e: Expr): Seq[Expr] = e match { + case Let(_, _, bd) => Seq(bd) + case IfExpr(_, t, e) => Seq(t, e) // if-else always has braces anyway + case _ => Seq() + } - protected def requiresBraces(ex: Tree, within: Option[Tree]) = (ex, within) match { - case (e: Expr, _) if isSimpleExpr(e) => false - case (e: Expr, Some(within: Expr)) if noBracesSub(within) contains e => false - case (e: Expr, Some(_)) => true - case _ => false - } + protected def requiresBraces(ex: Tree, within: Option[Tree]) = (ex, within) match { + case (e: Expr, _) if isSimpleExpr(e) => false + case (e: Expr, Some(within: Expr)) if noBracesSub(within) contains e => false + case (e: Expr, Some(_)) => true + case _ => false + } - protected def precedence(ex: Expr): Int = ex match { - case (pa: PrettyPrintable) => pa.printPrecedence - // 0: Letters - case (_: ElementOfSet | _: Modulo) => 0 - // 1: | - case (_: Or | _: BVOr) => 1 - // 2: ^ - case (_: BVXor) => 2 - // 3: & - case (_: And | _: BVAnd | _: SetIntersection) => 3 - // 4: < > - case ( - _: GreaterThan | _: GreaterEquals | _: LessEquals | _: LessThan | - _: BVAShiftRight | _: BVLShiftRight | _: BVShiftLeft - ) => 4 - // 5: = ! - case (_: Equals | _: Not | _: Implies) => 5 - // 6: : - // 7: + - - case (_: Plus | _: Minus | _: SetUnion | _: SetDifference | _: StringConcat) => 7 - // 8: * / % - case (_: Times | _: Division | _: Remainder) => 8 - // 9: Other special characters - case _ => 9 - } + protected def precedence(ex: Expr): Int = ex match { + case (pa: PrettyPrintable) => pa.printPrecedence + // 0: Letters + case (_: ElementOfSet | _: Modulo) => 0 + // 1: | + case (_: Or | _: BVOr) => 1 + // 2: ^ + case (_: BVXor) => 2 + // 3: & + case (_: And | _: BVAnd | _: SetIntersection) => 3 + // 4: < > + case ( + _: GreaterThan | _: GreaterEquals | _: LessEquals | _: LessThan | + _: BVAShiftRight | _: BVLShiftRight | _: BVShiftLeft + ) => 4 + // 5: = ! + case (_: Equals | _: Not | _: Implies) => 5 + // 6: : + // 7: + - + case (_: Plus | _: Minus | _: SetUnion | _: SetDifference | _: StringConcat) => 7 + // 8: * / % + case (_: Times | _: Division | _: Remainder) => 8 + // 9: Other special characters + case _ => 9 + } - protected def requiresParentheses(ex: Tree, within: Option[Tree]): Boolean = (ex, within) match { - case (pa: PrettyPrintable, _) => pa.printRequiresParentheses(within) - case (_, None) => false - case (_, Some( - _: Definition | _: Let | _: IfExpr | _: ADT | _: Lambda | _: Choose | _: Tuple - )) => false - case (ex: StringConcat, Some(_: StringConcat)) => false - case (_, Some(_: FunctionInvocation)) => false - case (ie: IfExpr, _) => true - case (e1: Expr, Some(e2: Expr)) if precedence(e1) > precedence(e2) => false - case (_, _) => true - } + protected def requiresParentheses(ex: Tree, within: Option[Tree]): Boolean = (ex, within) match { + case (pa: PrettyPrintable, _) => pa.printRequiresParentheses(within) + case (_, None) => false + case (_, Some( + _: Definition | _: Let | _: IfExpr | _: ADT | _: Lambda | _: Choose | _: Tuple + )) => false + case (ex: StringConcat, Some(_: StringConcat)) => false + case (_, Some(_: FunctionInvocation)) => false + case (ie: IfExpr, _) => true + case (e1: Expr, Some(e2: Expr)) if precedence(e1) > precedence(e2) => false + case (_, _) => true } implicit class PrintWrapper(val f: PrinterContext => Any) { @@ -412,8 +422,7 @@ trait Printers { implicit class PrintingHelper(val sc: StringContext) { def p(args: Any*)(implicit ctx: PrinterContext): Unit = { - val printer = ctx.printer - val sb = printer.sb + val sb = ctx.sb val strings = sc.parts.iterator val expressions = args.iterator @@ -464,10 +473,10 @@ trait Printers { nctx.current :: nctx.parents } val nctx2 = nctx.copy(parents = parents, current = t) - printer.pp(t)(nctx2) + pp(t)(nctx2) case id: Identifier => - val name = if (ctx.printer.opts.printUniqueIds) { + val name = if (ctx.opts.printUniqueIds) { id.uniqueName } else { id.toString @@ -514,29 +523,10 @@ trait Printers { def isSimpleExpr: Boolean = false } - abstract class PrettyPrinterFactory { - def create(opts: PrinterOptions, osym: Option[Symbols]): PrettyPrinter - - def apply(tree: Tree, opts: PrinterOptions = PrinterOptions(), osym: Option[Symbols] = None): String = { - val printer = create(opts, osym) - val ctx = PrinterContext(tree, Nil, opts.baseIndent, printer) - printer.pp(tree)(ctx) - printer.toString - } - - def apply(tree: Tree, ctx: InoxContext): String = { - val opts = PrinterOptions.fromContext(ctx) - apply(tree, opts, None) - } - - def apply(tree: Tree, ctx: InoxContext, sym: Symbols): String = { - val opts = PrinterOptions.fromContext(ctx) - apply(tree, opts, Some(sym)) - } - } - - object PrettyPrinter extends PrettyPrinterFactory { - def create(opts: PrinterOptions, osym: Option[Symbols]) = new PrettyPrinter(opts, osym) + def prettyPrint(tree: Tree, opts: PrinterOptions = PrinterOptions()): String = { + val ctx = PrinterContext(tree, Nil, opts.baseIndent, opts) + pp(tree)(ctx) + ctx.sb.toString } } diff --git a/src/main/scala/inox/ast/Trees.scala b/src/main/scala/inox/ast/Trees.scala index 5f342c5a85fa8895e3c3440fc556de2adbacb459..ac08971ac895faa1befb1246efba8f007d636be2 100644 --- a/src/main/scala/inox/ast/Trees.scala +++ b/src/main/scala/inox/ast/Trees.scala @@ -27,7 +27,7 @@ trait Trees // @EK: toString is considered harmful for non-internal things. Use asString(ctx) instead. - def asString(implicit opts: PrinterOptions): String = PrettyPrinter(this, opts) + def asString(implicit opts: PrinterOptions): String = prettyPrint(this, opts) override def toString = asString(PrinterOptions.fromContext(InoxContext.printNames)) } diff --git a/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala b/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala index caa22aeb8fdc1cb6311e408a3236f56d0e4c675e..d9e5836ddbd499e3da88424d2cf046537052256f 100644 --- a/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala +++ b/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala @@ -128,10 +128,16 @@ trait DatatypeTemplates { self: Templates => val newBool: Variable = Variable(FreshIdentifier("b", true), BooleanType) storeCond(pathVar, newBool) - iff(and(pathVar, IsInstanceOf(expr, tpe)), newBool) for (vd <- tcons.fields) { rec(newBool, ADTSelector(AsInstanceOf(expr, tpe), vd.id)) } + + val vars = types.keys.toSet ++ functions.keys + guardedExprs.flatMap(_._2.flatMap(exprOps.variablesOf)) + + if (vars(newBool)) { + iff(and(pathVar, IsInstanceOf(expr, tpe)), newBool) + } } } } @@ -253,6 +259,7 @@ trait DatatypeTemplates { self: Templates => } def unroll: Clauses = if (typeInfos.isEmpty) Seq.empty else { + println("unrolling datatypes") val blockers = typeInfos.filter(_._2._1 <= currentGeneration).toSeq.map(_._1) val newClauses = new scala.collection.mutable.ListBuffer[Encoded] diff --git a/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala b/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala index 942fa17da1e4cebf6f5d819a0e2e8e9527d27dd5..d6ba9205cea613f26384340a1713076e026bf011 100644 --- a/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala +++ b/src/main/scala/inox/solvers/unrolling/LambdaTemplates.scala @@ -271,8 +271,6 @@ trait LambdaTemplates { self: Templates => val typeBlocker = encodeSymbol(Variable(FreshIdentifier("t"), BooleanType)) typeBlockers += value -> typeBlocker - val clauses = registerSymbol(typeBlocker, value, to) - val (b, extClauses) = if (knownFree(tpe) contains caller) { (blocker, Seq.empty) } else { @@ -289,6 +287,9 @@ trait LambdaTemplates { self: Templates => (firstB, Seq(clause)) } + registerParent(typeBlocker, b) + val clauses = registerSymbol(typeBlocker, value, to) + clauses ++ extClauses :+ mkImplies(b, typeBlocker) } } diff --git a/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala b/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala index 24339f73fdf43eb2c58ebe3505e6430833598053..62c214b6915791cef732950c83b661999390e5f5 100644 --- a/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala +++ b/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala @@ -188,7 +188,7 @@ trait TemplateGenerator { self: Templates => val xrec = rec(pathVar, x, pol) iff(and(pathVar, xrec), newBool) - iff(and(pathVar, not(xrec)), not(newExpr)) + storeGuarded(pathVar, implies(not(xrec), not(newExpr))) recAnd(newBool, xs) @@ -216,7 +216,7 @@ trait TemplateGenerator { self: Templates => storeCond(pathVar, newBool) val xrec = rec(pathVar, x, None) - iff(and(pathVar, xrec), newExpr) + storeGuarded(pathVar, implies(xrec, newExpr)) iff(and(pathVar, not(xrec)), newBool) recOr(newBool, xs) diff --git a/src/main/scala/inox/solvers/unrolling/Templates.scala b/src/main/scala/inox/solvers/unrolling/Templates.scala index 3e0af30b5d11fb73d77e5fd5068bbe289049ebc9..fd358008adaa9370af658090676464e04c36ad45 100644 --- a/src/main/scala/inox/solvers/unrolling/Templates.scala +++ b/src/main/scala/inox/solvers/unrolling/Templates.scala @@ -120,6 +120,10 @@ trait Templates extends TemplateGenerator } } + protected def registerParent(child: Encoded, parent: Encoded): Unit = { + condImplied += child -> (condImplied(child) + parent) + } + protected def blockerParents(b: Encoded): Set[Encoded] = condImplied(b) protected def blockerChildren(b: Encoded): Set[Encoded] = condImplies(b)