-
Notifications
You must be signed in to change notification settings - Fork 57
Addressing some issues in AntiAliasing #1245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
01cd938
to
667ef3d
Compare
case Assignment(v, expr) => | ||
// We explicitly override this case to not have the recursion go through `v` and potentially taking the above case | ||
// (otherwise, we could get something like `env.rewritings(v.toVal) = expr` which may not be well-defined). | ||
Assignment(v, transform(expr, env)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If v
belongs to env.rewritings
, doesn't that mean that we've added a LetVar
to the rewritings map? That would be incorrect in itself, so if this case is cropping up we might have an underlying issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that the only v
s for which this case is problematic are those that are of a mutable type and val
-defined (such as val x = if (b1) a1 else a2
in invalid/i916a1
).
Such rewriting in env
is added by:
stainless/core/src/main/scala/stainless/extraction/imperative/AntiAliasing.scala
Lines 417 to 434 in e91c5d6
if (targets.isSuccess) { | |
// This branch handles all cases when targets can be precisely computed, namely when | |
// 1. newExpr is a fresh expression | |
// 2. newExpr is a precise alias to an existing variable | |
val rewriting = targets.get.foldRight(vd.toVariable : Expr) { | |
case (Target(r, Some(cond), path), rewriting) => | |
val wrapped = path.wrap(r).getOrElse( | |
throw MalformedStainlessCode(l, "Unsupported `val` in AntiAliasing (conditional target)") | |
) | |
IfExpr(cond, wrapped, rewriting) | |
case (Target(r, None, path), rewriting) => | |
path.wrap(r).getOrElse( | |
throw MalformedStainlessCode(l, "Unsupported `val` in AntiAliasing (unconditional target)") | |
) | |
} | |
val newBody = transform(b, env withRewritings Map(vd -> rewriting) withBinding vd) | |
LetVar(vd, newExpr, newBody).copiedFrom(l) |
and seems to be intended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But when are we seeing an Assignment(x, ...)
? Scala vals can't be assigned, are we applying a transformation twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val x
is transformed into a var x
and it is re-assigned each time we modify one of its components.
If we e.g. see x.a = 123
, it is transformed into an assignment: x = A(123)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. Thanks for bearing with me :)
I don't like the fact that we're applying transform
to assignments produced during the phase since it makes it difficult to distinguish issues in the phase from issues in the input program. I think it would be worth cleaning up these cases to avoid applying transform
to the generated Assignment
expressions. For example,
should probably be something like below instead
val applied = updatedTarget(target, v)
Assignment(target.receiver, transform(applied, env)).copiedFrom(up)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good note, I'll address that in a separate PR
val combinedCond = Some(cond).zip(effectCond).map { | ||
case (BooleanLiteral(b1), c2) => | ||
if (b1) c2 else BooleanLiteral(false) | ||
case (c1, BooleanLiteral(b2)) => | ||
if (b2) c1 else BooleanLiteral(false) | ||
case (c1, c2) => | ||
And(c1, c2) | ||
}.getOrElse(cond) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can replace this by andJoin(cond +: effectCond.toSeq)
for better readability.
Hopefully fixes the underlying problems of #916, #1099, and #1122 without introducing new bugs...