diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala index 42d53fc24645c08931641eae4db37df3020e7143..d8ac22b21b4f387077cd9f583f8958124da657cd 100644 --- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala @@ -86,12 +86,6 @@ trait AbstractZ3Solver } } - object LeonType { - def unapply(a: Z3Sort): Option[(TypeTree)] = { - sorts.getLeon(a).map(tt => tt) - } - } - class Bijection[A, B] { var leonToZ3 = Map[A, B]() var z3ToLeon = Map[B, A]() @@ -559,7 +553,7 @@ trait AbstractZ3Solver case Not(e) => z3.mkNot(rec(e)) case IntLiteral(v) => z3.mkInt(v, typeToSort(Int32Type)) case InfiniteIntegerLiteral(v) => z3.mkNumeral(v.toString, typeToSort(IntegerType)) - case CharLiteral(c) => z3.mkInt(c, typeToSort(Int32Type)) + case CharLiteral(c) => z3.mkInt(c, typeToSort(CharType)) case BooleanLiteral(v) => if (v) z3.mkTrue() else z3.mkFalse() case UnitLiteral() => unitValue case Equals(l, r) => z3.mkEq(rec( l ), rec( r ) ) @@ -728,17 +722,32 @@ trait AbstractZ3Solver } } - protected[leon] def fromZ3Formula(model: Z3Model, tree : Z3AST) : Expr = { - def rec(t: Z3AST): Expr = { + protected[leon] def fromZ3Formula(model: Z3Model, tree: Z3AST, tpe: TypeTree) : Expr = { + + // This is unsafe and should be avoided because sorts<->types are not a bijection + // For instance, both Int32Type and CharType compile to BV32 + + def recGuess(t: Z3AST): Expr = { + val s = z3.getSort(t) + rec(t, sorts.toLeon(s)) + } + + def rec(t: Z3AST, tpe: TypeTree): Expr = { val kind = z3.getASTKind(t) - val sort = z3.getSort(t) kind match { case Z3NumeralIntAST(Some(v)) => { val leading = t.toString.substring(0, 2 min t.toString.length) if(leading == "#x") { _root_.smtlib.common.Hexadecimal.fromString(t.toString.substring(2)) match { - case Some(hexa) => IntLiteral(hexa.toInt) + case Some(hexa) => + tpe match { + case Int32Type => IntLiteral(hexa.toInt) + case CharType => CharLiteral(hexa.toInt.toChar) + case _ => + println("Unexpected target type for BV value: " + tpe) + throw new CantTranslateException(t) + } case None => { println("Z3NumeralIntAST with None: " + t) throw new CantTranslateException(t) @@ -750,7 +759,14 @@ trait AbstractZ3Solver } case Z3NumeralIntAST(None) => { _root_.smtlib.common.Hexadecimal.fromString(t.toString.substring(2)) match { - case Some(hexa) => IntLiteral(hexa.toInt) + case Some(hexa) => + tpe match { + case Int32Type => IntLiteral(hexa.toInt) + case CharType => CharLiteral(hexa.toInt.toChar) + case _ => + println("Unexpected target type for BV value: " + tpe) + throw new CantTranslateException(t) + } case None => { println("Z3NumeralIntAST with None: " + t) throw new CantTranslateException(t) @@ -764,87 +780,85 @@ trait AbstractZ3Solver } else if(functions containsZ3 decl) { val tfd = functions.toLeon(decl) assert(tfd.params.size == argsSize) - FunctionInvocation(tfd, args.map(rec)) + FunctionInvocation(tfd, args.zip(tfd.params).map{ case (a, p) => rec(a, p.getType) }) } else if(argsSize == 1 && (reverseADTTesters contains decl)) { val cct = reverseADTTesters(decl) - CaseClassInstanceOf(cct, rec(args.head)) + CaseClassInstanceOf(cct, rec(args.head, cct.root)) } else if(argsSize == 1 && (reverseADTFieldSelectors contains decl)) { val (cct, fid) = reverseADTFieldSelectors(decl) - CaseClassSelector(cct, rec(args.head), fid) + CaseClassSelector(cct, rec(args.head, cct), fid) } else if(reverseADTConstructors contains decl) { val cct = reverseADTConstructors(decl) assert(argsSize == cct.fields.size) - CaseClass(cct, args.map(rec)) + CaseClass(cct, args.zip(cct.fieldsTypes).map{ case (a, t) => rec(a, t) }) } else if (generics containsZ3 decl) { generics.toLeon(decl) } else { - sort match { - case LeonType(tp: TypeParameter) => + tpe match { + case tp: TypeParameter => val id = t.toString.split("!").last.toInt GenericValue(tp, id) - case LeonType(tp: TupleType) => - val rargs = args.map(rec) + case TupleType(ts) => + val rargs = args.zip(ts).map{ case (a, t) => rec(a, t) } tupleWrap(rargs) - case LeonType(at @ ArrayType(dt)) => + case at @ ArrayType(dt) => assert(args.size == 2) - val length = rec(args(1)) match { - case InfiniteIntegerLiteral(length) => length.toInt + val length = rec(args(1), Int32Type) match { case IntLiteral(length) => length case _ => throw new CantTranslateException(t) } model.getArrayValue(args(0)) match { case None => throw new CantTranslateException(t) case Some((map, elseZ3Value)) => - val elseValue = rec(elseZ3Value) + val elseValue = rec(elseZ3Value, dt) val valuesMap = map.map { case (k,v) => - val index = rec(k) match { - case InfiniteIntegerLiteral(index) => index.toInt + val index = rec(k, Int32Type) match { case IntLiteral(index) => index case _ => throw new CantTranslateException(t) } - index -> rec(v) + index -> rec(v, dt) } finiteArray(valuesMap, Some(elseValue, IntLiteral(length)), dt) } - case LeonType(tpe @ MapType(kt, vt)) => + case tpe @ MapType(kt, vt) => model.getArrayValue(t) match { case None => throw new CantTranslateException(t) case Some((map, elseZ3Value)) => val values = map.toSeq.map { case (k, v) => (k, z3.getASTKind(v)) }.collect { case (k, Z3AppAST(cons, arg :: Nil)) if cons == mapRangeSomeConstructors(vt) => - (rec(k), rec(arg)) + (rec(k, kt), rec(arg, vt)) } finiteMap(values, kt, vt) } - case LeonType(FunctionType(fts, tt)) => + case FunctionType(fts, tt) => model.getArrayValue(t) match { case None => throw new CantTranslateException(t) case Some((map, elseZ3Value)) => - val leonElseValue = rec(elseZ3Value) - val leonMap = map.toSeq.map(p => rec(p._1) -> rec(p._2)) + val leonElseValue = rec(elseZ3Value, tt) + val leonMap = map.toSeq.map(p => rec(p._1, tupleTypeWrap(fts)) -> rec(p._2, tt)) finiteLambda(leonElseValue, leonMap, fts) } - case LeonType(tpe @ SetType(dt)) => + case tpe @ SetType(dt) => model.getSetValue(t) match { case None => throw new CantTranslateException(t) case Some(set) => - val elems = set.map(e => rec(e)) + val elems = set.map(e => rec(e, dt)) finiteSet(elems, dt) } - case LeonType(UnitType) => + case UnitType => UnitLiteral() case _ => import Z3DeclKind._ - val rargs = args.map(rec) + val rargs = args.map(recGuess) z3.getDeclKind(decl) match { case OpTrue => BooleanLiteral(true) case OpFalse => BooleanLiteral(false) @@ -879,59 +893,12 @@ trait AbstractZ3Solver throw new CantTranslateException(t) } } - rec(tree) - } - - // Tries to convert a Z3AST into a *ground* Expr. Doesn't try very hard, because - // 1) we assume Z3 simplifies ground terms, so why match for +, etc, and - // 2) we use this precisely in one context, where we know function invocations won't show up, etc. - protected[leon] def asGround(tree : Z3AST) : Option[Expr] = { - val e = new Exception("Not ground.") - - def rec(t : Z3AST) : Expr = z3.getASTKind(t) match { - case Z3AppAST(decl, args) => { - val argsSize = args.size - if(functions containsZ3 decl) { - val tfd = functions.toLeon(decl) - FunctionInvocation(tfd, args.map(rec)) - } else if(argsSize == 1 && reverseADTTesters.isDefinedAt(decl)) { - val cct = reverseADTTesters(decl) - CaseClassInstanceOf(cct, rec(args.head)) - } else if(argsSize == 1 && reverseADTFieldSelectors.isDefinedAt(decl)) { - val (cct, fid) = reverseADTFieldSelectors(decl) - CaseClassSelector(cct, rec(args.head), fid) - } else if(reverseADTConstructors.isDefinedAt(decl)) { - val cct = reverseADTConstructors(decl) - CaseClass(cct, args.map(rec)) - } else { - z3.getSort(t) match { - case LeonType(t : TupleType) => - tupleWrap(args.map(rec)) - - case _ => - import Z3DeclKind._ - z3.getDeclKind(decl) match { - case OpTrue => BooleanLiteral(true) - case OpFalse => BooleanLiteral(false) - case _ => throw e - } - } - } - } - case Z3NumeralIntAST(Some(v)) => InfiniteIntegerLiteral(v) - case _ => throw e - } - - try { - Some(rec(tree)) - } catch { - case e : Exception => None - } + rec(tree, tpe) } - protected[leon] def softFromZ3Formula(model: Z3Model, tree : Z3AST) : Option[Expr] = { + protected[leon] def softFromZ3Formula(model: Z3Model, tree: Z3AST, tpe: TypeTree) : Option[Expr] = { try { - Some(fromZ3Formula(model, tree)) + Some(fromZ3Formula(model, tree, tpe)) } catch { case e: CantTranslateException => None } diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala index b13345ae42bb1abc24180b12514d542f557452ac..ede0429dd5725d42c0587a2c10ed46a2c53747a6 100644 --- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala @@ -11,6 +11,7 @@ import purescala.Definitions._ import purescala.Expressions._ import purescala.Constructors._ import purescala.ExprOps._ +import purescala.Types._ import solvers.templates._ @@ -64,11 +65,11 @@ class FairZ3Solver(val context : LeonContext, val program: Program) val tfd = functions.toLeon(p._1) if (!tfd.hasImplementation) { val (cses, default) = p._2 - val ite = cses.foldLeft(fromZ3Formula(model, default))((expr, q) => IfExpr( + val ite = cses.foldLeft(fromZ3Formula(model, default, tfd.returnType))((expr, q) => IfExpr( andJoin( - q._1.zip(tfd.params).map(a12 => Equals(fromZ3Formula(model, a12._1), Variable(a12._2.id))) + q._1.zip(tfd.params).map(a12 => Equals(fromZ3Formula(model, a12._1, a12._2.getType), Variable(a12._2.id))) ), - fromZ3Formula(model, q._2), + fromZ3Formula(model, q._2, tfd.returnType), expr)) Seq((tfd.id, ite)) } else Seq() @@ -79,7 +80,7 @@ class FairZ3Solver(val context : LeonContext, val program: Program) if(functions containsZ3 p._1) { val tfd = functions.toLeon(p._1) if(!tfd.hasImplementation) { - Seq((tfd.id, fromZ3Formula(model, p._2))) + Seq((tfd.id, fromZ3Formula(model, p._2, tfd.returnType))) } else Seq() } else Seq() }).toMap @@ -223,7 +224,7 @@ class FairZ3Solver(val context : LeonContext, val program: Program) val assumptionsAsZ3Set: Set[Z3AST] = assumptionsAsZ3.toSet def z3CoreToCore(core: Seq[Z3AST]): Set[Expr] = { - core.filter(assumptionsAsZ3Set).map(ast => fromZ3Formula(null, ast) match { + core.filter(assumptionsAsZ3Set).map(ast => fromZ3Formula(null, ast, BooleanType) match { case n @ Not(Variable(_)) => n case v @ Variable(_) => v case x => scala.sys.error("Impossible element extracted from core: " + ast + " (as Leon tree : " + x + ")") diff --git a/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala b/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala index ffc0bdbbce4fbccc4e1e2d3372e482d5b1c78471..08589a2e35cc909435aa865535c5c141806ebe8b 100644 --- a/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala @@ -66,7 +66,7 @@ class UninterpretedZ3Solver(val context : LeonContext, val program: Program) } def getUnsatCore = { - solver.getUnsatCore().map(ast => fromZ3Formula(null, ast) match { + solver.getUnsatCore().map(ast => fromZ3Formula(null, ast, BooleanType) match { case n @ Not(Variable(_)) => n case v @ Variable(_) => v case x => scala.sys.error("Impossible element extracted from core: " + ast + " (as Leon tree : " + x + ")") diff --git a/src/main/scala/leon/solvers/z3/Z3ModelReconstruction.scala b/src/main/scala/leon/solvers/z3/Z3ModelReconstruction.scala index be40e8fafce0ddd2d577d2872392e6352233945f..2abe022723668d44a1fbdea3b251b61b5fad9c80 100644 --- a/src/main/scala/leon/solvers/z3/Z3ModelReconstruction.scala +++ b/src/main/scala/leon/solvers/z3/Z3ModelReconstruction.scala @@ -24,12 +24,12 @@ trait Z3ModelReconstruction { case BooleanType => model.evalAs[Boolean](z3ID).map(BooleanLiteral) case Int32Type => model.evalAs[Int](z3ID).map(IntLiteral).orElse{ - model.eval(z3ID).flatMap(t => softFromZ3Formula(model, t)) + model.eval(z3ID).flatMap(t => softFromZ3Formula(model, t, Int32Type)) } case IntegerType => model.evalAs[Int](z3ID).map(InfiniteIntegerLiteral(_)) case other => model.eval(z3ID) match { case None => None - case Some(t) => softFromZ3Formula(model, t) + case Some(t) => softFromZ3Formula(model, t, other) } } }