From 849de6aa80e4c437130bb557f9083cc277f952ee Mon Sep 17 00:00:00 2001
From: Manos Koukoutos <emmanouil.koukoutos@epfl.ch>
Date: Tue, 8 Sep 2015 14:58:56 +0200
Subject: [PATCH] Fix MethodLifting and improvements

Make signature of IsInstanceOf consistent with other Expr's
Add isInstOf Constructor
Correctly handle This in instantiateType
Correctly handle This in MethodLifting when it belongs to a subtype
An extra unit test
---
 .../scala/leon/codegen/CodeGeneration.scala   |  2 +-
 .../leon/evaluators/RecursiveEvaluator.scala  |  2 +-
 .../frontends/scalac/CodeExtraction.scala     |  2 +-
 .../scala/leon/purescala/Constructors.scala   | 10 ++++++++
 src/main/scala/leon/purescala/ExprOps.scala   |  6 ++---
 .../scala/leon/purescala/Expressions.scala    |  4 ++--
 .../scala/leon/purescala/Extractors.scala     |  4 ++--
 .../scala/leon/purescala/MethodLifting.scala  | 24 +++++++++++--------
 .../scala/leon/purescala/PrettyPrinter.scala  |  2 +-
 src/main/scala/leon/purescala/TypeOps.scala   |  7 ++++--
 .../leon/solvers/smtlib/SMTLIBSolver.scala    |  2 +-
 .../leon/solvers/z3/AbstractZ3Solver.scala    |  8 +++----
 .../scala/leon/synthesis/rules/ADTDual.scala  |  4 ++--
 .../leon/synthesis/rules/ADTInduction.scala   |  2 +-
 .../synthesis/rules/ADTLongInduction.scala    |  2 +-
 .../scala/leon/synthesis/rules/ADTSplit.scala |  4 ++--
 .../synthesis/rules/EquivalentInputs.scala    |  2 +-
 .../leon/termination/SelfCallsProcessor.scala |  2 +-
 src/main/scala/leon/utils/TypingPhase.scala   |  6 ++---
 .../leon/verification/InductionTactic.scala   |  4 ++--
 .../leon/verification/InjectAsserts.scala     |  2 +-
 .../leon/unit/purescala/TypeOpsSuite.scala    |  3 ++-
 22 files changed, 61 insertions(+), 43 deletions(-)

diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index f4bb00795..1e37626f0 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -279,7 +279,7 @@ trait CodeGeneration {
         }
         ch << InvokeSpecial(ccName, constructorName, ccApplySig)
 
-      case IsInstanceOf(cct, e) =>
+      case IsInstanceOf(e, cct) =>
         val (ccName, _) = leonClassToJVMInfo(cct.classDef).getOrElse {
           throw CompilationException("Unknown class : " + cct.id)
         }
diff --git a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
index 3f4a67f48..38710837f 100644
--- a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
+++ b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
@@ -231,7 +231,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
         throw RuntimeError("Cast error: cannot cast "+le.asString+" to "+ct.asString) 
       }
 
-    case IsInstanceOf(ct, expr) =>
+    case IsInstanceOf(expr, ct) =>
       val le = e(expr)
       BooleanLiteral(isSubtypeOf(le.getType, ct))
 
diff --git a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
index 2c8325042..0a6633aa4 100644
--- a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
+++ b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
@@ -1427,7 +1427,7 @@ trait CodeExtraction extends ASTExtractors {
                 if(rootType != testedExprRootType) {
                   outOfSubsetError(tr, "isInstanceOf can only be used with compatible classes")
                 } else {
-                  IsInstanceOf(ct, ccRec)
+                  IsInstanceOf(ccRec, ct)
                 }
               }
             case _ =>
diff --git a/src/main/scala/leon/purescala/Constructors.scala b/src/main/scala/leon/purescala/Constructors.scala
index 5f217f229..22697b7df 100644
--- a/src/main/scala/leon/purescala/Constructors.scala
+++ b/src/main/scala/leon/purescala/Constructors.scala
@@ -383,8 +383,18 @@ object Constructors {
     if (isSubtypeOf(expr.getType, tpe)) {
       expr
     } else {
+      //println(s"$expr:${expr.getType} is not a subtype of $tpe")
       AsInstanceOf(expr, tpe)
     }
   }
 
+  def isInstOf(expr: Expr, tpe: ClassType) = {
+    if (isSubtypeOf(expr.getType, tpe)) {
+      BooleanLiteral(true)
+    } else {
+      IsInstanceOf(expr, tpe)
+    }
+
+  }
+
 }
diff --git a/src/main/scala/leon/purescala/ExprOps.scala b/src/main/scala/leon/purescala/ExprOps.scala
index 69267f7af..91d36d7a9 100644
--- a/src/main/scala/leon/purescala/ExprOps.scala
+++ b/src/main/scala/leon/purescala/ExprOps.scala
@@ -771,7 +771,7 @@ object ExprOps {
           if (ct.parent.isEmpty) {
             bind(ob, in)
           } else {
-            and(IsInstanceOf(ct, in), bind(ob, in))
+            and(IsInstanceOf(in, ct), bind(ob, in))
           }
 
         case CaseClassPattern(ob, cct, subps) =>
@@ -779,7 +779,7 @@ object ExprOps {
           val pairs = cct.fields.map(_.id).toList zip subps.toList
           val subTests = pairs.map(p => rec(caseClassSelector(cct, in, p._1), p._2))
           val together = and(bind(ob, in) +: subTests :_*)
-          and(IsInstanceOf(cct, in), together)
+          and(IsInstanceOf(in, cct), together)
 
         case TuplePattern(ob, subps) =>
           val TupleType(tpes) = in.getType
@@ -1326,7 +1326,7 @@ object ExprOps {
         case ccd: CaseClassDef =>
           val cct = CaseClassType(ccd, tps)
 
-          val isType = IsInstanceOf(cct, Variable(on))
+          val isType = IsInstanceOf(Variable(on), cct)
 
           val recSelectors = cct.fields.collect { 
             case vd if vd.getType == on.getType => vd.id
diff --git a/src/main/scala/leon/purescala/Expressions.scala b/src/main/scala/leon/purescala/Expressions.scala
index 7882a6269..b44a4b9f8 100644
--- a/src/main/scala/leon/purescala/Expressions.scala
+++ b/src/main/scala/leon/purescala/Expressions.scala
@@ -327,7 +327,7 @@ object Expressions {
         binder,
         FunctionInvocation(unapplyFun, Seq(scrut)),
         IfExpr(
-          IsInstanceOf(someType, Variable(binder)),
+          IsInstanceOf(Variable(binder), someType),
           someCase(CaseClassSelector(someType, Variable(binder), someValue.id)),
           noneCase
         )
@@ -424,7 +424,7 @@ object Expressions {
   }
 
   /** $encodingof `.isInstanceOf[...]` */
-  case class IsInstanceOf(classType: ClassType, expr: Expr) extends Expr {
+  case class IsInstanceOf(expr: Expr, classType: ClassType) extends Expr {
     val getType = BooleanType
   }
 
diff --git a/src/main/scala/leon/purescala/Extractors.scala b/src/main/scala/leon/purescala/Extractors.scala
index c8d54731c..ca6a21fb0 100644
--- a/src/main/scala/leon/purescala/Extractors.scala
+++ b/src/main/scala/leon/purescala/Extractors.scala
@@ -31,8 +31,8 @@ object Extractors {
         Some((Seq(t), (es: Seq[Expr]) => SetCardinality(es.head)))
       case CaseClassSelector(cd, e, sel) =>
         Some((Seq(e), (es: Seq[Expr]) => caseClassSelector(cd, es.head, sel)))
-      case IsInstanceOf(ct, e) =>
-        Some((Seq(e), (es: Seq[Expr]) => IsInstanceOf(ct, es.head)))
+      case IsInstanceOf(e, ct) =>
+        Some((Seq(e), (es: Seq[Expr]) => IsInstanceOf(es.head, ct)))
       case AsInstanceOf(e, ct) =>
         Some((Seq(e), (es: Seq[Expr]) => asInstOf(es.head, ct)))
       case TupleSelect(t, i) =>
diff --git a/src/main/scala/leon/purescala/MethodLifting.scala b/src/main/scala/leon/purescala/MethodLifting.scala
index 277803109..4848bf10e 100644
--- a/src/main/scala/leon/purescala/MethodLifting.scala
+++ b/src/main/scala/leon/purescala/MethodLifting.scala
@@ -79,8 +79,8 @@ object MethodLifting extends TransformationPhase {
         val at = acd.typed
         val binder = FreshIdentifier(acd.id.name.toLowerCase, at, true)
         def subst(e: Expr): Expr = e match {
-          case This(`at`) =>
-            Variable(binder)
+          case This(ct) =>
+            asInstOf(Variable(binder), ct)
           case e =>
             e
         }
@@ -125,9 +125,9 @@ object MethodLifting extends TransformationPhase {
           newFd.fullBody,
           Some(and(
             prec,
-            IsInstanceOf(
-              c.typed(root.tparams.map{ _.tp }),
-              This(root.typed)
+            isInstOf(
+              This(root.typed),
+              c.typed(root.tparams.map{ _.tp })
             )
           ))
         ))
@@ -158,14 +158,18 @@ object MethodLifting extends TransformationPhase {
         nfd.addFlag(IsMethod(cd))
 
         if (cd.knownDescendants.forall( cd => (cd.methods ++ cd.fields).forall(_.id != fd.id))) {
-          val paramsMap = fd.params.zip(fdParams).map{case (x,y) => (x.id, y.id)}.toMap
           // Don't need to compose methods
-          nfd.fullBody = postMap {
-            case th@This(ct) if ct.classDef == cd =>
-              Some(receiver.toVariable.setPos(th))
+          val paramsMap = fd.params.zip(fdParams).map{case (x,y) => (x.id, y.id)}.toMap
+          def thisToReceiver(e: Expr): Option[Expr] = e match {
+            case th@This(ct) =>
+              Some(asInstOf(receiver.toVariable, ct).setPos(th))
             case _ =>
               None
-          }(instantiateType(nfd.fullBody, tparamsMap, paramsMap))
+          }
+
+          val insTp: Expr => Expr = instantiateType(_, tparamsMap, paramsMap)
+
+          nfd.fullBody = insTp( postMap(thisToReceiver)(insTp(nfd.fullBody)) )
         } else {
           // We need to compose methods of subclasses
 
diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala
index c9005ec2d..6d020cc71 100644
--- a/src/main/scala/leon/purescala/PrettyPrinter.scala
+++ b/src/main/scala/leon/purescala/PrettyPrinter.scala
@@ -167,7 +167,7 @@ class PrettyPrinter(opts: PrinterOptions,
       case Choose(pred)         => p"choose($pred)"
       case e @ Error(tpe, err)  => p"""error[$tpe]("$err")"""
       case AsInstanceOf(e, ct)  => p"""$e.asInstanceOf[$ct]"""
-      case IsInstanceOf(cct, e) =>
+      case IsInstanceOf(e, cct) =>
         if (cct.classDef.isCaseObject) {
           p"($e == $cct)"
         } else {
diff --git a/src/main/scala/leon/purescala/TypeOps.scala b/src/main/scala/leon/purescala/TypeOps.scala
index 0eac83d63..5c68340e6 100644
--- a/src/main/scala/leon/purescala/TypeOps.scala
+++ b/src/main/scala/leon/purescala/TypeOps.scala
@@ -273,14 +273,17 @@ object TypeOps {
           case mi @ MethodInvocation(r, cd, TypedFunDef(fd, tps), args) =>
             MethodInvocation(srec(r), cd, TypedFunDef(fd, tps.map(tpeSub)), args.map(srec)).copiedFrom(mi)
 
+          case th @ This(ct) =>
+            This(tpeSub(ct).asInstanceOf[ClassType]).copiedFrom(th)
+
           case cc @ CaseClass(ct, args) =>
             CaseClass(tpeSub(ct).asInstanceOf[CaseClassType], args.map(srec)).copiedFrom(cc)
 
           case cc @ CaseClassSelector(ct, e, sel) =>
             caseClassSelector(tpeSub(ct).asInstanceOf[CaseClassType], srec(e), sel).copiedFrom(cc)
 
-          case cc @ IsInstanceOf(ct, e) =>
-            IsInstanceOf(tpeSub(ct).asInstanceOf[ClassType], srec(e)).copiedFrom(cc)
+          case cc @ IsInstanceOf(e, ct) =>
+            IsInstanceOf(srec(e), tpeSub(ct).asInstanceOf[ClassType]).copiedFrom(cc)
 
           case cc @ AsInstanceOf(e, ct) =>
             AsInstanceOf(srec(e), tpeSub(ct).asInstanceOf[ClassType]).copiedFrom(cc)
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
index aaf65f508..bcf8a5fa1 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
@@ -333,7 +333,7 @@ abstract class SMTLIBSolver(val context: LeonContext,
       case AsInstanceOf(expr, cct) =>
         toSMT(expr)
 
-      case IsInstanceOf(cct, e) =>
+      case IsInstanceOf(e, cct) =>
         declareSort(cct)
         val cases = cct match {
           case act: AbstractClassType =>
diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
index 07943a8b9..bfa1d9c16 100644
--- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
@@ -426,16 +426,16 @@ trait AbstractZ3Solver extends Solver {
       case AsInstanceOf(expr, ct) =>
         rec(expr)
 
-      case IsInstanceOf(act: AbstractClassType, e) =>
+      case IsInstanceOf(e, act: AbstractClassType) =>
         act.knownCCDescendants match {
           case Seq(cct) =>
-            rec(IsInstanceOf(cct, e))
+            rec(IsInstanceOf(e, cct))
           case more =>
             val i = FreshIdentifier("e", act, alwaysShowUniqueID = true)
-            rec(Let(i, e, orJoin(more map(IsInstanceOf(_, Variable(i))))))
+            rec(Let(i, e, orJoin(more map(IsInstanceOf(Variable(i), _)))))
         }
 
-      case IsInstanceOf(cct: CaseClassType, e) =>
+      case IsInstanceOf(e, cct: CaseClassType) =>
         typeToSort(cct) // Making sure the sort is defined
         val tester = testers.toB(cct)
         tester(rec(e))
diff --git a/src/main/scala/leon/synthesis/rules/ADTDual.scala b/src/main/scala/leon/synthesis/rules/ADTDual.scala
index f8770aafd..392670edf 100644
--- a/src/main/scala/leon/synthesis/rules/ADTDual.scala
+++ b/src/main/scala/leon/synthesis/rules/ADTDual.scala
@@ -18,10 +18,10 @@ case object ADTDual extends NormalizingRule("ADTDual") {
 
     val (toRemove, toAdd) = exprs.collect {
       case eq @ Equals(cc @ CaseClass(ct, args), e) if (variablesOf(e) -- as).isEmpty && (variablesOf(cc) & xs).nonEmpty =>
-        (eq, IsInstanceOf(ct, e) +: (ct.fields zip args).map{ case (vd, ex) => Equals(ex, caseClassSelector(ct, e, vd.id)) } )
+        (eq, IsInstanceOf(e, ct) +: (ct.fields zip args).map{ case (vd, ex) => Equals(ex, caseClassSelector(ct, e, vd.id)) } )
 
       case eq @ Equals(e, cc @ CaseClass(ct, args)) if (variablesOf(e) -- as).isEmpty && (variablesOf(cc) & xs).nonEmpty =>
-        (eq, IsInstanceOf(ct, e) +: (ct.fields zip args).map{ case (vd, ex) => Equals(ex, caseClassSelector(ct, e, vd.id)) } )
+        (eq, IsInstanceOf(e, ct) +: (ct.fields zip args).map{ case (vd, ex) => Equals(ex, caseClassSelector(ct, e, vd.id)) } )
     }.unzip
 
     if (toRemove.nonEmpty) {
diff --git a/src/main/scala/leon/synthesis/rules/ADTInduction.scala b/src/main/scala/leon/synthesis/rules/ADTInduction.scala
index 3b6df4524..9f379108f 100644
--- a/src/main/scala/leon/synthesis/rules/ADTInduction.scala
+++ b/src/main/scala/leon/synthesis/rules/ADTInduction.scala
@@ -68,7 +68,7 @@ case object ADTInduction extends Rule("ADT Induction") {
           val subPC  = substAll(Map(inductOn -> CaseClass(cct, newIds.map(Variable))), innerPC)
           val subWS  = substAll(Map(inductOn -> CaseClass(cct, newIds.map(Variable))), innerWS)
 
-          val subPre = IsInstanceOf(cct, Variable(origId))
+          val subPre = IsInstanceOf(Variable(origId), cct)
 
           val subProblem = Problem(inputs ::: residualArgs, subWS, andJoin(subPC :: postFs), subPhi, p.xs)
 
diff --git a/src/main/scala/leon/synthesis/rules/ADTLongInduction.scala b/src/main/scala/leon/synthesis/rules/ADTLongInduction.scala
index 093897196..4a5adceed 100644
--- a/src/main/scala/leon/synthesis/rules/ADTLongInduction.scala
+++ b/src/main/scala/leon/synthesis/rules/ADTLongInduction.scala
@@ -82,7 +82,7 @@ case object ADTLongInduction extends Rule("ADT Long Induction") {
 
                 val newMap = trMap.mapValues(v => substAll(Map(id -> CaseClass(cct, subIds.map(Variable))), v))
 
-                InductCase(newIds, newCalls, newPattern, and(pc, IsInstanceOf(cct, Variable(id))), newMap)
+                InductCase(newIds, newCalls, newPattern, and(pc, IsInstanceOf(Variable(id), cct)), newMap)
               }
             }).flatten
           } else {
diff --git a/src/main/scala/leon/synthesis/rules/ADTSplit.scala b/src/main/scala/leon/synthesis/rules/ADTSplit.scala
index 6485d3ffa..294c6e137 100644
--- a/src/main/scala/leon/synthesis/rules/ADTSplit.scala
+++ b/src/main/scala/leon/synthesis/rules/ADTSplit.scala
@@ -23,7 +23,7 @@ case object ADTSplit extends Rule("ADT Split.") {
         val optCases = for (dcd <- cd.knownDescendants.sortBy(_.id.name)) yield dcd match {
           case ccd : CaseClassDef =>
             val cct = CaseClassType(ccd, tpes)
-            val toSat = and(p.pc, IsInstanceOf(cct, Variable(id)))
+            val toSat = and(p.pc, IsInstanceOf(Variable(id), cct))
 
             val isImplied = solver.solveSAT(toSat) match {
               case (Some(false), _) => true
@@ -86,7 +86,7 @@ case object ADTSplit extends Rule("ADT Split.") {
                 val substs = (for ((field,arg) <- cct.fields zip problem.as ) yield {
                   (arg, caseClassSelector(cct, id.toVariable, field.id))
                 }).toMap
-                globalPre ::= and(IsInstanceOf(cct, Variable(id)), replaceFromIDs(substs, sol.pre))
+                globalPre ::= and(IsInstanceOf(Variable(id), cct), replaceFromIDs(substs, sol.pre))
               } else {
                 globalPre ::= BooleanLiteral(true)
               }
diff --git a/src/main/scala/leon/synthesis/rules/EquivalentInputs.scala b/src/main/scala/leon/synthesis/rules/EquivalentInputs.scala
index c4acb5721..227dd691c 100644
--- a/src/main/scala/leon/synthesis/rules/EquivalentInputs.scala
+++ b/src/main/scala/leon/synthesis/rules/EquivalentInputs.scala
@@ -22,7 +22,7 @@ case object EquivalentInputs extends NormalizingRule("EquivalentInputs") {
 
       val clauses = allClauses.filterNot(instanceOfs.toSet)
 
-      val ccSubsts = for (IsInstanceOf(cct: CaseClassType, s) <- instanceOfs) yield {
+      val ccSubsts = for (IsInstanceOf(s, cct: CaseClassType) <- instanceOfs) yield {
 
         val fieldsVals = (for (f <- cct.fields) yield {
           val id = f.id
diff --git a/src/main/scala/leon/termination/SelfCallsProcessor.scala b/src/main/scala/leon/termination/SelfCallsProcessor.scala
index b8fe65f48..157dbce24 100644
--- a/src/main/scala/leon/termination/SelfCallsProcessor.scala
+++ b/src/main/scala/leon/termination/SelfCallsProcessor.scala
@@ -52,7 +52,7 @@ class SelfCallsProcessor(val checker: TerminationChecker) extends Processor {
       case Not(expr: Expr) => rec(expr)
       case Equals(lhs: Expr, rhs: Expr) => rec(lhs) || rec(rhs)
       case CaseClass(ct, args: Seq[Expr]) => args.exists(arg => rec(arg)) 
-      case IsInstanceOf(ct, expr: Expr) => rec(expr)
+      case IsInstanceOf(expr: Expr, ct) => rec(expr)
       case AsInstanceOf(expr: Expr, ct) => rec(expr)
       case CaseClassSelector(ct, caseClassExpr, selector) => rec(caseClassExpr)
       case Plus(lhs: Expr, rhs: Expr) => rec(lhs) || rec(rhs)
diff --git a/src/main/scala/leon/utils/TypingPhase.scala b/src/main/scala/leon/utils/TypingPhase.scala
index 05648fc9f..cb0f37ab5 100644
--- a/src/main/scala/leon/utils/TypingPhase.scala
+++ b/src/main/scala/leon/utils/TypingPhase.scala
@@ -35,7 +35,7 @@ object TypingPhase extends LeonPhase[Program, Program] {
       fd.precondition = {
         val argTypesPreconditions = fd.params.flatMap(arg => arg.getType match {
           case cct: ClassType if cct.parent.isDefined =>
-            Seq(IsInstanceOf(cct, arg.id.toVariable))
+            Seq(IsInstanceOf(arg.id.toVariable, cct))
           case at: ArrayType =>
             Seq(GreaterEquals(ArrayLength(arg.id.toVariable), IntLiteral(0)))
           case _ =>
@@ -57,7 +57,7 @@ object TypingPhase extends LeonPhase[Program, Program] {
             case Some(p) =>
               Some(Lambda(Seq(ValDef(resId)), and(
                 application(p, Seq(Variable(resId))),
-                IsInstanceOf(ct, Variable(resId))
+                IsInstanceOf(Variable(resId), ct)
               ).setPos(p)).setPos(p))
 
             case None =>
@@ -65,7 +65,7 @@ object TypingPhase extends LeonPhase[Program, Program] {
                 case Some(df: DefinedPosition) => df.focusEnd
                 case _ => NoPosition
               }
-              Some(Lambda(Seq(ValDef(resId)), IsInstanceOf(ct, Variable(resId))).setPos(pos))
+              Some(Lambda(Seq(ValDef(resId)), IsInstanceOf(Variable(resId), ct)).setPos(pos))
           }
         }
         case _ => fd.postcondition
diff --git a/src/main/scala/leon/verification/InductionTactic.scala b/src/main/scala/leon/verification/InductionTactic.scala
index 9e06e4abd..74b7b99af 100644
--- a/src/main/scala/leon/verification/InductionTactic.scala
+++ b/src/main/scala/leon/verification/InductionTactic.scala
@@ -40,7 +40,7 @@ class InductionTactic(vctx: VerificationContext) extends DefaultTactic(vctx) {
           }
 
           val vc = implies(
-            and(IsInstanceOf(cct, arg.toVariable), precOrTrue(fd)),
+            and(IsInstanceOf(arg.toVariable, cct), precOrTrue(fd)),
             implies(andJoin(subCases), application(post, Seq(body)))
           )
 
@@ -77,7 +77,7 @@ class InductionTactic(vctx: VerificationContext) extends DefaultTactic(vctx) {
           }
 
           val vc = implies(
-            andJoin(Seq(IsInstanceOf(cct, arg.toVariable), precOrTrue(fd), path) ++ subCases),
+            andJoin(Seq(IsInstanceOf(arg.toVariable, cct), precOrTrue(fd), path) ++ subCases),
             tfd.withParamSubst(args, pre)
           )
 
diff --git a/src/main/scala/leon/verification/InjectAsserts.scala b/src/main/scala/leon/verification/InjectAsserts.scala
index 871662815..8244da31a 100644
--- a/src/main/scala/leon/verification/InjectAsserts.scala
+++ b/src/main/scala/leon/verification/InjectAsserts.scala
@@ -36,7 +36,7 @@ object InjectAsserts extends LeonPhase[Program, Program] {
           Some(Assert(MapIsDefinedAt(m, k), Some("Map undefined at this index"), e).setPos(e))
 
         case e @ AsInstanceOf(expr, ct)  =>
-          Some(Assert(IsInstanceOf(ct, expr),
+          Some(Assert(IsInstanceOf(expr, ct),
                       Some("Cast error"),
                       e
                      ).setPos(e))
diff --git a/src/test/scala/leon/unit/purescala/TypeOpsSuite.scala b/src/test/scala/leon/unit/purescala/TypeOpsSuite.scala
index 5d8867550..57f37ed34 100644
--- a/src/test/scala/leon/unit/purescala/TypeOpsSuite.scala
+++ b/src/test/scala/leon/unit/purescala/TypeOpsSuite.scala
@@ -18,7 +18,6 @@ class TypeOpsSuite extends LeonTestSuite with helpers.WithLikelyEq with helpers.
 
     val tp2   = TypeParameter.fresh("A")
     val tp3   = TypeParameter.fresh("B")
-    val tp4   = TypeParameter.fresh("C")
 
     val listD = AbstractClassDef(FreshIdentifier("List"), Seq(tpD), None)
     val listT = listD.typed
@@ -58,6 +57,8 @@ class TypeOpsSuite extends LeonTestSuite with helpers.WithLikelyEq with helpers.
     assert(canBeSubtypeOf(tp,           Seq(tp2), tp2, rhsFixed = true).isEmpty,    "T </: A with A free but lhs is fixed")
 
     assert(canBeSubtypeOf(listT,        Seq(tp),  listD.typed(Seq(tp2)), rhsFixed = true).isDefined,    "List[T] <: List[A] with T free and rhs fixed")
+
+    assert(isSubtypeOf(listD.typed, listD.typed), "List[T] <: List[T]")
   }
 
 }
-- 
GitLab