diff --git a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala index 9e97c6c7bfc097c811d86bc825e5082a9be7c7c1..502563f0fe0a32546ded292141430af4be31779a 100644 --- a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala +++ b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala @@ -14,7 +14,7 @@ import purescala.Extractors._ import purescala.Quantification._ import solvers.{Model, HenkinModel} import solvers.SolverFactory -import synthesis.ConvertHoles.convertHoles +import synthesis.ConversionPhase.convertHoles import leon.purescala.ExprOps abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int) extends Evaluator(ctx, prog) { diff --git a/src/main/scala/leon/purescala/CompleteAbstractDefinitions.scala b/src/main/scala/leon/purescala/CompleteAbstractDefinitions.scala deleted file mode 100644 index db508eaf7964d394f5e11b98590beaa1532a9d5b..0000000000000000000000000000000000000000 --- a/src/main/scala/leon/purescala/CompleteAbstractDefinitions.scala +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ - -package leon -package purescala - -import Common._ -import Definitions._ -import Expressions._ - -object CompleteAbstractDefinitions extends UnitPhase[Program] { - - val name = "Materialize abstract functions" - val description = "Inject fake choose-like body in abstract definitions" - - def apply(ctx: LeonContext, program: Program) = { - for (u <- program.units; m <- u.modules; fd <- m.definedFunctions; if fd.body.isEmpty) { - val post = fd.postcondition getOrElse ( - Lambda(Seq(ValDef(FreshIdentifier("res", fd.returnType))), BooleanLiteral(true)) - ) - fd.body = Some(Choose(post)) - } - } - -} diff --git a/src/main/scala/leon/purescala/Expressions.scala b/src/main/scala/leon/purescala/Expressions.scala index 7216652a427e6784142a17f69c730fa61e2ff0aa..b834eb9f1270bca728b2cdbaa63bb98a37b0dd49 100644 --- a/src/main/scala/leon/purescala/Expressions.scala +++ b/src/main/scala/leon/purescala/Expressions.scala @@ -886,7 +886,7 @@ object Expressions { /** $encodingof a synthesizable hole in a program. Represented by `???[tpe]` * in Leon source code. * - * A [[Hole]] gets transformed into a [[Choose]] construct during [[leon.synthesis.ConvertHoles the ConvertHoles phase]]. + * A [[Hole]] gets transformed into a [[Choose]] construct during [[leon.synthesis.ConversionPhase the ConvertHoles phase]]. */ case class Hole(tpe: TypeTree, alts: Seq[Expr]) extends Expr with Extractable { val getType = tpe diff --git a/src/main/scala/leon/purescala/Quantification.scala b/src/main/scala/leon/purescala/Quantification.scala index 38fa0ae9f81190096aa4f19cbd5a5a988dbfb249..1b00ed1b41a5053fb07a94695b00f595d54453ba 100644 --- a/src/main/scala/leon/purescala/Quantification.scala +++ b/src/main/scala/leon/purescala/Quantification.scala @@ -19,7 +19,7 @@ object Quantification { qargs: A => Set[B] ): Seq[Set[A]] = { def rec(oms: Seq[A], mSet: Set[A], qss: Seq[Set[B]]): Seq[Set[A]] = { - if (qss.exists(_ == quantified)) { + if (qss.contains(quantified)) { Seq(mSet) } else { var res = Seq.empty[Set[A]] @@ -126,12 +126,11 @@ object Quantification { ctx.reporter.warning("E-matching isn't possible without matchers!") if (matchers.exists { case (_, args) => - args.exists(arg => arg match { + args.exists{ case QuantificationMatcher(_, _) => false case Variable(id) => false - case _ if (variablesOf(arg) & quantified).nonEmpty => true - case _ => false - }) + case arg => (variablesOf(arg) & quantified).nonEmpty + } }) ctx.reporter.warning("Matcher arguments must have simple form in " + conjunct) val freeMatchers = matchers.collect { case (Variable(id), args) if free(id) => id -> args } @@ -143,7 +142,7 @@ object Quantification { })) } - if (id2Quant.filter(_._2.nonEmpty).groupBy(_._2).size >= 1) + if (id2Quant.filter(_._2.nonEmpty).groupBy(_._2).nonEmpty) ctx.reporter.warning("Multiple matchers must provide bijective matching in " + conjunct) fold[Set[Identifier]] { case (m, children) => diff --git a/src/main/scala/leon/synthesis/ConversionPhase.scala b/src/main/scala/leon/synthesis/ConversionPhase.scala new file mode 100644 index 0000000000000000000000000000000000000000..bab77552bf1c6cfb8d3f151aed97c66bca6904ce --- /dev/null +++ b/src/main/scala/leon/synthesis/ConversionPhase.scala @@ -0,0 +1,185 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +package leon +package synthesis + +import purescala.Common._ +import purescala.Expressions._ +import purescala.Types._ +import purescala.ExprOps._ +import purescala.Definitions._ +import purescala.Constructors._ + +object ConversionPhase extends UnitPhase[Program] { + val name = "Eliminate holes, withOracle and abstract definitions" + val description = "Convert Holes, withOracle found in bodies and abstract function bodies to equivalent Choose" + + /** + * This phase does 3 things: + * + * 1) Converts a body with "withOracle{ .. }" into a choose construct: + * + * def foo(a: T) = { + * require(..a..) + * withOracle { o => + * expr(a,o) ensuring { x => post(x) } + * } + * } + * + * gets converted into: + * + * def foo(a: T) { + * require(..a..) + * val o = choose { (o) => { + * val res = expr(a, o) + * pred(res) + * } + * expr(a,o) + * } ensuring { res => + * pred(res) + * } + * + * + * 2) Converts a body with "???" into a choose construct: + * + * def foo(a: T) = { + * require(..a..) + * expr(a, ???) + * } ensuring { x => post(x) } + * + * gets converted into: + * + * def foo(a: T) = { + * require(..a..) + * val h = choose ( h' => + * val res = expr(a, h') + * post(res) + * ) + * expr(a, h) + * } ensuring { res => + * post(res) + * } + * + * 3) Completes abstract definitions: + * + * def foo(a: T) = { + * require(..a..) + * ??? + * } ensuring { res => + * post(res) + * } + * + * gets converted to: + * + * def foo(a: T) = { + * require(..a..) + * choose(x => post(x)) + * } + * + */ + + def convertHoles(e : Expr, ctx : LeonContext) : Expr = { + val (pre, body, post) = breakDownSpecs(e) + + // Ensure that holes are not found in pre and/or post conditions + (pre ++ post).foreach { + preTraversal{ + case h : Hole => + ctx.reporter.error(s"Holes are not supported in pre- or postconditions. @ ${h.getPos}") + case wo: WithOracle => + ctx.reporter.error(s"WithOracle expressions are not supported in pre- or postconditions: ${wo.asString(ctx)} @ ${wo.getPos}") + case _ => + } + } + + def toExpr(h: Hole): (Expr, List[Identifier]) = { + h.alts match { + case Seq() => + val h1 = FreshIdentifier("hole", h.getType, true) + (h1.toVariable, List(h1)) + + case Seq(v) => + val h1 = FreshIdentifier("hole", BooleanType, true) + val h2 = FreshIdentifier("hole", h.getType, true) + (IfExpr(h1.toVariable, h2.toVariable, v), List(h1, h2)) + + case exs => + var ids: List[Identifier] = Nil + val ex = exs.init.foldRight(exs.last)({ (e: Expr, r: Expr) => + val h = FreshIdentifier("hole", BooleanType, true) + ids ::= h + IfExpr(h.toVariable, e, r) + }) + + (ex, ids.reverse) + } + } + + body match { + case Some(body) => + var holes = List[Identifier]() + + val withoutHoles = preMap { + case h : Hole => + val (expr, ids) = toExpr(h) + + holes ++= ids + + Some(expr) + case wo @ WithOracle(os, b) => + withoutSpec(b) map { pred => + val chooseOs = os.map(_.freshen) + + val pred = post.getOrElse( // FIXME: We need to freshen variables + Lambda(chooseOs.map(ValDef(_)), BooleanLiteral(true)) + ) + + letTuple(os, Choose(pred), b) + } + case _ => + None + }(body) + + if (holes.nonEmpty) { + val cids: List[Identifier] = holes.map(_.freshen) + val hToFresh = (holes zip cids.map(_.toVariable)).toMap + + val spec = post match { + case Some(post: Lambda) => + val asLet = letTuple(post.args.map(_.id), withoutHoles, post.body) + + Lambda(cids.map(ValDef(_)), replaceFromIDs(hToFresh, asLet)) + + case _ => + Lambda(cids.map(ValDef(_)), BooleanLiteral(true)) + } + + val choose = Choose(spec) + + val newBody = if (holes.size == 1) { + replaceFromIDs(Map(holes.head -> choose), withoutHoles) + } else { + letTuple(holes, choose, withoutHoles) + } + + withPostcondition(withPrecondition(newBody, pre), post) + + } else { + e + } + + case None => + val newPost = post getOrElse Lambda(Seq(ValDef(FreshIdentifier("res", e.getType))), BooleanLiteral(true)) + withPrecondition(Choose(newPost), pre) + } + } + + + def apply(ctx: LeonContext, pgm: Program): Unit = { + // TODO: remove side-effects + for (fd <- pgm.definedFunctions) { + fd.fullBody = convertHoles(fd.fullBody,ctx) + } + } + +} diff --git a/src/main/scala/leon/synthesis/ConvertHoles.scala b/src/main/scala/leon/synthesis/ConvertHoles.scala deleted file mode 100644 index 8c08f05e89f6fcb133609802ffe46c686e40fa36..0000000000000000000000000000000000000000 --- a/src/main/scala/leon/synthesis/ConvertHoles.scala +++ /dev/null @@ -1,131 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ - -package leon -package synthesis - -import purescala.Common._ -import purescala.Expressions._ -import purescala.Types._ -import purescala.ExprOps._ -import purescala.Definitions._ -import purescala.Constructors._ - -object ConvertHoles extends TransformationPhase { - val name = "Convert Holes to Choose" - val description = "Convert Holes found in bodies to equivalent Choose" - - /** - * This phase converts a body with "???" into a choose construct: - * - * def foo(a: T) = { - * require(..a..) - * expr(a, ???) - * } ensuring { x => post(x) } - * - * gets converted into: - * - * def foo(a: T) { - * require(..a..) - * val h = choose ( h' => - * val res = expr(a, h') - * post(res) - * ) - * expr(a, h) - * } ensuring { res => - * post(res) - * } - * - */ - - def convertHoles(e : Expr, ctx : LeonContext) : Expr = { - val (pre, body, post) = breakDownSpecs(e) - - // Ensure that holes are not found in pre and/or post conditions - (pre ++ post).foreach { - preTraversal{ - case h : Hole => - ctx.reporter.error("Holes are not supported in pre- or postconditions. @"+ h.getPos) - case _ => - } - } - - body match { - case Some(body) => - var holes = List[Identifier]() - - val withoutHoles = preMap { - case h : Hole => - val (expr, ids) = toExpr(h) - - holes ++= ids - - Some(expr) - case _ => - None - }(body) - - if (holes.nonEmpty) { - val cids: List[Identifier] = holes.map(_.freshen) - val hToFresh = (holes zip cids.map(_.toVariable)).toMap - - val spec = post match { - case Some(post: Lambda) => - val asLet = letTuple(post.args.map(_.id), withoutHoles, post.body) - - Lambda(cids.map(ValDef(_)), replaceFromIDs(hToFresh, asLet)) - - case _ => - Lambda(cids.map(ValDef(_)), BooleanLiteral(true)) - } - - val choose = Choose(spec) - - val newBody = if (holes.size == 1) { - replaceFromIDs(Map(holes.head -> choose), withoutHoles) - } else { - letTuple(holes, choose, withoutHoles) - } - - withPostcondition(withPrecondition(newBody, pre), post) - - } else { - e - } - - case None => e - } - } - - - def apply(ctx: LeonContext, pgm: Program): Program = { - // TODO: remove side-effects - for (fd <- pgm.definedFunctions) { - fd.fullBody = convertHoles(fd.fullBody,ctx) - } - - pgm - } - - def toExpr(h: Hole): (Expr, List[Identifier]) = { - h.alts match { - case Seq() => - val h1 = FreshIdentifier("hole", h.getType, true) - (h1.toVariable, List(h1)) - - case Seq(v) => - val h1 = FreshIdentifier("hole", BooleanType, true) - val h2 = FreshIdentifier("hole", h.getType, true) - (IfExpr(h1.toVariable, h2.toVariable, v), List(h1, h2)) - - case exs => - var ids: List[Identifier] = Nil - val ex = exs.init.foldRight(exs.last)({ (e: Expr, r: Expr) => - val h = FreshIdentifier("hole", BooleanType, true) - ids ::= h - IfExpr(h.toVariable, e, r) - }) - - (ex, ids.reverse) - } - } -} diff --git a/src/main/scala/leon/synthesis/ConvertWithOracle.scala b/src/main/scala/leon/synthesis/ConvertWithOracle.scala deleted file mode 100644 index ac3785c43e454431ebf18ecc2df4dcec78a6a16b..0000000000000000000000000000000000000000 --- a/src/main/scala/leon/synthesis/ConvertWithOracle.scala +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ - -package leon -package synthesis - -import purescala.Expressions._ -import purescala.ExprOps._ -import purescala.Definitions._ -import purescala.Constructors._ - -object ConvertWithOracle extends TransformationPhase { - val name = "Convert WithOracle to Choose" - val description = "Convert WithOracle found in bodies to equivalent Choose" - - /** - * This phase converts a body with "withOracle{ .. }" into a choose construct: - * - * def foo(a: T) = { - * require(..a..) - * withOracle { o => - * expr(a,o) ensuring { x => post(x) } - * } - * } - * - * gets converted into: - * - * def foo(a: T) { - * require(..a..) - * val o = choose { (o) => { - * val res = expr(a, o) - * pred(res) - * } - * expr(a,o) - * } ensuring { res => - * pred(res) - * } - * - */ - def apply(ctx: LeonContext, pgm: Program): Program = { - // TODO: Remove side-effects - - pgm.definedFunctions.foreach(fd => { - if (fd.hasBody) { - val body = preMap { - case wo @ WithOracle(os, b) => - withoutSpec(b) match { - case Some(pred) => - val chooseOs = os.map(_.freshen) - - val pred = postconditionOf(b) match { - case Some(post) => - post // FIXME we need to freshen variables - case None => - Lambda(chooseOs.map(ValDef(_)), BooleanLiteral(true)) - } - - Some(letTuple(os, Choose(pred), b)) - case None => - None - } - case _ => None - }(fd.body.get) - - fd.body = Some(body) - } - - // Ensure that holes are not found in pre and/or post conditions - fd.precondition.foreach { - preTraversal{ - case _: WithOracle => - ctx.reporter.error("WithOracle expressions are not supported in preconditions. (function "+fd.id.asString(ctx)+")") - case _ => - } - } - - fd.postcondition.foreach { - preTraversal{ - case _: WithOracle => - ctx.reporter.error("WithOracle expressions are not supported in postconditions. (function "+fd.id.asString(ctx)+")") - case _ => - } - } - - }) - - pgm - } -} diff --git a/src/main/scala/leon/utils/PreprocessingPhase.scala b/src/main/scala/leon/utils/PreprocessingPhase.scala index 38b770ba19a468977cf8018c2ac7d438140525a5..87d1003150995eb236e5f3abb738450516c5b7f7 100644 --- a/src/main/scala/leon/utils/PreprocessingPhase.scala +++ b/src/main/scala/leon/utils/PreprocessingPhase.scala @@ -7,11 +7,10 @@ import leon.purescala._ import leon.purescala.Definitions.Program import leon.purescala.Quantification.CheckForalls import leon.solvers.isabelle.AdaptationPhase -import leon.synthesis.{ConvertWithOracle, ConvertHoles} import leon.verification.InjectAsserts -import leon.xlang.XLangDesugaringPhase +import leon.xlang.{NoXLangFeaturesChecking, XLangDesugaringPhase} -class PreprocessingPhase(private val desugarXLang: Boolean = false) extends LeonPhase[Program, Program] { +class PreprocessingPhase(desugarXLang: Boolean = false) extends LeonPhase[Program, Program] { val name = "preprocessing" val description = "Various preprocessings on Leon programs" @@ -26,13 +25,18 @@ class PreprocessingPhase(private val desugarXLang: Boolean = false) extends Leon } } + val checkX = if (desugarXLang) { + NoopPhase[Program]() + } else { + NoXLangFeaturesChecking + } + val pipeBegin = debugTrees("Program after extraction") andThen + checkX andThen MethodLifting andThen TypingPhase andThen - ConvertWithOracle andThen - ConvertHoles andThen - CompleteAbstractDefinitions andThen + synthesis.ConversionPhase andThen CheckADTFieldsTypes andThen InjectAsserts andThen InliningPhase andThen @@ -42,7 +46,7 @@ class PreprocessingPhase(private val desugarXLang: Boolean = false) extends Leon XLangDesugaringPhase andThen debugTrees("Program after xlang desugaring") } else { - xlang.NoXLangFeaturesChecking + NoopPhase[Program]() } val phases =