Skip to content

Commit

Permalink
Transform requires to assertions in exported functions in GenC
Browse files Browse the repository at this point in the history
  • Loading branch information
jad-hamza committed Oct 16, 2021
1 parent b6528ec commit 137373a
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ package phases
import extraction._
import extraction.throwing. { trees => tt }

import genc.ExtraOps._

trait GhostElimination extends inox.transformers.Transformer {
override val s: throwing.Trees
override val s: tt.type = tt // to use `isExported` from `genc.ExtraOps.FunDefOps`
override val t: throwing.Trees
val symbols: s.Symbols
val context: inox.Context
Expand Down Expand Up @@ -61,8 +63,23 @@ trait GhostElimination extends inox.transformers.Transformer {
}

def transform(fd: s.FunDef, env: Env): t.FunDef = {
val specced = s.exprOps.BodyWithSpecs(fd.fullBody)
val body = specced.letsAndBody
import s.exprOps._
val specced = BodyWithSpecs(fd.fullBody)
val body = if (fd.isExported)
specced.specs.foldRight(specced.body) {
case (spec @ LetInSpec(vd, e), acc) => s.Let(vd, e, acc).setPos(spec)
case (spec @ Precondition(s.Annotated(cond, flags)), acc) if flags.contains(s.Ghost) => acc
case (spec @ Precondition(cond), acc) => s.Assert(cond, Some("Dynamic precondition check"), acc).setPos(spec)
case (_, acc) => acc
}
else
specced.letsAndBody

if (fd.id.name == "FSWrite") {
println("isExported", fd.isExported)
println("specs\n", specced.specs.mkString("\n"))
println("body", body)
}

new t.FunDef(
fd.id,
Expand Down
21 changes: 6 additions & 15 deletions core/src/main/scala/stainless/genc/phases/Scala2IRPhase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -528,9 +528,10 @@ private class S2IRImpl(val context: inox.Context, val ctxDB: FunCtxDB, val syms:
val paramEnv: Seq[((ValDef, Type), CIR.ValDef)] = paramKeys zip params

val newBindings = env.bindings ++ ctxEnv ++ paramEnv
val bodyWithoutSpecs = exprOps.BodyWithSpecs(fa.fullBody).letsAndBody

// Recurse on the FunDef body, and not the TypedFunDef one, in order to keep the correct identifiers.
CIR.FunBodyAST(rec(fa.fullBody)(env.copy(bindings = newBindings), tm1))
CIR.FunBodyAST(rec(bodyWithoutSpecs)(env.copy(bindings = newBindings), tm1))
}

// Now that we have a body, we can fully build the FunDef
Expand Down Expand Up @@ -663,15 +664,13 @@ private class S2IRImpl(val context: inox.Context, val ctxDB: FunCtxDB, val syms:
if flags.contains(DropVCs) && expr1 == expr2 && tpe1 == tpe2 =>
rec(expr1)

/* Ignore static assertions */
case Require(pred, body) if env.inExported =>
case Decreases(_, body) => rec(body)

case Assert(cond, Some("Dynamic precondition check"), body) =>
CIR.buildBlock(Seq(
CIR.Assert(rec(pred)),
CIR.Assert(rec(cond)),
rec(body)
))
case Require(_, body) => rec(body)
case Decreases(_, body) => rec(body)
case Ensuring(body, _) => rec(body)
case Assert(_, _, body) => rec(body)
case Assume(_, body) => rec(body)

Expand Down Expand Up @@ -736,14 +735,6 @@ private class S2IRImpl(val context: inox.Context, val ctxDB: FunCtxDB, val syms:

case fi @ FunctionInvocation(id, tps, args) =>
val fd = syms.getFunction(id)
// FIXME: requires do not generate assertions at the moment
// if (fd.isExported && fd.hasPrecondition) {
// reporter.warning(fi.getPos,
// s"Exported functions (${fd.id.asString}) generate C assertions for requires, " +
// "so invoking them from within Stainless is not recommended as Stainless already checks " +
// "that the requires are respected"
// )
// }
val tfd = fd.typed(tps)
val fun = rec(Outer(fd), tps)(tm0, env.copy(inExported = fd.isExported))
implicit val tm1 = tm0 ++ tfd.tpSubst
Expand Down

0 comments on commit 137373a

Please sign in to comment.