From 4553c205f50da90e3fc939d2f7c683f88764d98a Mon Sep 17 00:00:00 2001
From: Etienne Kneuss <colder@php.net>
Date: Mon, 10 Feb 2014 11:15:36 +0100
Subject: [PATCH] Fix @induct creating incorrect type-parametric VCs.

Improve debugging capabilities of Pretty/Scala printer w.r.t. types
---
 .../scala/leon/purescala/PrettyPrinter.scala  | 16 ++++++----
 .../scala/leon/purescala/PrinterOptions.scala |  1 +
 .../scala/leon/purescala/ScalaPrinter.scala   |  3 --
 .../scala/leon/solvers/z3/FairZ3Solver.scala  |  1 +
 .../leon/verification/InductionTactic.scala   | 29 +++++++------------
 5 files changed, 23 insertions(+), 27 deletions(-)

diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala
index a5962a428..98345cba1 100644
--- a/src/main/scala/leon/purescala/PrettyPrinter.scala
+++ b/src/main/scala/leon/purescala/PrettyPrinter.scala
@@ -69,11 +69,15 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe
         }
 
       case Variable(id) =>
-        //sb.append("(")
-        pp(id, p)
-        //sb.append(": ")
-        //pp(id.getType, p)
-        //sb.append(")")
+        if (opts.printTypes) {
+          sb.append("(")
+          pp(id, p)
+          sb.append(": ")
+          pp(id.getType, p)
+          sb.append(")")
+        } else {
+          pp(id, p)
+        }
 
       case LetTuple(bs,d,e) =>
         sb.append("(let ")
@@ -483,7 +487,7 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe
         pp(tp, p)
 
       case TypeParameter(id) =>
-        sb.append(id.uniqueName)
+        pp(id, p)
 
       case _ => sb.append("Tree? (" + tree.getClass + ")")
     }
diff --git a/src/main/scala/leon/purescala/PrinterOptions.scala b/src/main/scala/leon/purescala/PrinterOptions.scala
index dc7b77aa2..597c15c68 100644
--- a/src/main/scala/leon/purescala/PrinterOptions.scala
+++ b/src/main/scala/leon/purescala/PrinterOptions.scala
@@ -3,5 +3,6 @@ package leon.purescala
 case class PrinterOptions (
   baseIndent: Int = 0,
   printPositions: Boolean = false,
+  printTypes: Boolean = false,
   printUniqueIds: Boolean = false
 )
diff --git a/src/main/scala/leon/purescala/ScalaPrinter.scala b/src/main/scala/leon/purescala/ScalaPrinter.scala
index 843e0905b..2347523cb 100644
--- a/src/main/scala/leon/purescala/ScalaPrinter.scala
+++ b/src/main/scala/leon/purescala/ScalaPrinter.scala
@@ -53,9 +53,6 @@ class ScalaPrinter(opts: PrinterOptions, sb: StringBuffer = new StringBuffer) ex
     var printPos = opts.printPositions
 
     tree match {
-      case Variable(id) => 
-        pp(id, p)
-
       case LetTuple(ids,d,e) =>
         optBraces { implicit lvl =>
           sb.append("val (" )
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index b3952e4fd..76f52585b 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -225,6 +225,7 @@ class FairZ3Solver(val context : LeonContext, val program: Program)
       // define an activating boolean...
       val template = getTemplate(expr)
 
+
       val z3args = for (vd <- template.tfd.args) yield {
         variables.getZ3(Variable(vd.id)) match {
           case Some(ast) =>
diff --git a/src/main/scala/leon/verification/InductionTactic.scala b/src/main/scala/leon/verification/InductionTactic.scala
index 91b92d981..781db8ce1 100644
--- a/src/main/scala/leon/verification/InductionTactic.scala
+++ b/src/main/scala/leon/verification/InductionTactic.scala
@@ -13,16 +13,10 @@ class InductionTactic(reporter: Reporter) extends DefaultTactic(reporter) {
   override val description = "Induction tactic for suitable functions"
   override val shortDescription = "induction"
 
-  private def firstAbsClassDef(args: Seq[VarDecl]) : Option[(AbstractClassDef, VarDecl)] = {
-    val filtered = args.filter(arg =>
-      arg.getType match {
-        case AbstractClassType(_, _) => true
-        case _ => false
-      })
-    if (filtered.size == 0) None else (filtered.head.getType match {
-      case AbstractClassType(classDef, _) => Some((classDef, filtered.head))
-      case _ => scala.sys.error("This should not happen.")
-    })
+  private def firstAbsClassDef(args: Seq[VarDecl]) : Option[(AbstractClassType, VarDecl)] = {
+    args.map(vd => (vd.getType, vd)).collect {
+      case (act: AbstractClassType, vd) => (act, vd)
+    }.headOption
   } 
 
   private def selectorsOfParentType(parentType: ClassType, cct: CaseClassType, expr: Expr) : Seq[Expr] = {
@@ -34,14 +28,13 @@ class InductionTactic(reporter: Reporter) extends DefaultTactic(reporter) {
 
   override def generatePostconditions(funDef: FunDef) : Seq[VerificationCondition] = {
     assert(funDef.body.isDefined)
-    val defaultPost = super.generatePostconditions(funDef)
     firstAbsClassDef(funDef.args) match {
-      case Some((classDef, arg)) =>
+      case Some((cct, arg)) =>
         val prec = funDef.precondition
         val optPost = funDef.postcondition
         val body = matchToIfThenElse(funDef.body.get)
         val argAsVar = arg.toVariable
-        val parentType = classDefToClassType(classDef)
+        val parentType = cct
 
         optPost match {
           case None =>
@@ -66,22 +59,22 @@ class InductionTactic(reporter: Reporter) extends DefaultTactic(reporter) {
                   })
                   Implies(And(inductiveHypothesis), withPrec)
                 }
-              new VerificationCondition(Implies(CaseClassInstanceOf(cct, argAsVar), conditionForChild), funDef, VCKind.Postcondition, this)
+              new VerificationCondition(Implies(CaseClassInstanceOf(cct, argAsVar), conditionForChild), funDef, VCKind.Postcondition, this).setPos(funDef)
             }
         }
 
       case None =>
-        reporter.warning("Induction tactic currently supports exactly one argument of abstract class type")
-        defaultPost
+        reporter.warning("Could not find abstract class type argument to induct on")
+        super.generatePostconditions(funDef)
     }
   }
 
   override def generatePreconditions(function: FunDef) : Seq[VerificationCondition] = {
     val defaultPrec = super.generatePreconditions(function)
     firstAbsClassDef(function.args) match {
-      case Some((classDef, arg)) => {
+      case Some((cct, arg)) => {
         val toRet = if(function.hasBody) {
-          val parentType = classDefToClassType(classDef)
+          val parentType = cct
           val cleanBody = expandLets(matchToIfThenElse(function.body.get))
 
           val allPathConds = collectWithPathCondition((t => t match {
-- 
GitLab