-
Notifications
You must be signed in to change notification settings - Fork 163
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
Boolean expressions do not short circuit as expected #2444
Comments
Great catch! Thanks for figuring out the problem. There is a design issue to figure out: in Fortran these operators do not short circuit. In C and Python they do. There are also proposals to Fortran both in terms of new operators or compiler options or even changes to the standard to make them short circuit. In terms of performance, it would be nice to not close door to possible optimizations. In terms of the bug above, I am guessing the ASR->LLVM evaluates all part of the expression and then uses "and" on the result. To short-circuit it, it should first evaluate the first, and only do the second if it is true. Probably the easiest for now is to set a flag in ASR for --- a/src/libasr/ASR.asdl
+++ b/src/libasr/ASR.asdl
@@ -277,7 +277,7 @@ expr
| LogicalConstant(bool value, ttype type)
| LogicalNot(expr arg, ttype type, expr? value)
| LogicalCompare(expr left, cmpop op, expr right, ttype type, expr? value)
- | LogicalBinOp(expr left, logicalbinop op, expr right, ttype type, expr? value)
+ | LogicalBinOp(expr left, logicalbinop op, expr right, bool short_circuit, ttype type, expr? value)
| ListConstant(expr* args, ttype type)
| ListLen(expr arg, ttype type, expr? value) Then in the backend it would generate the proper code. When would we not want to short-ciruict? I think never. I think we however want to have the freedom to rearrange the expression sometimes for optimizations. There is also an issue of emitting Fortran code from ASR, if we short-circuit by default, we can't just use This page has a lot of background on this topic: https://en.wikipedia.org/wiki/Short-circuit_evaluation, it seems we most likely require both, so the above diff is probably the best. |
Conceptually it looks like the following will cover all cases: --- a/src/libasr/ASR.asdl
+++ b/src/libasr/ASR.asdl
@@ -277,7 +277,7 @@ expr
| LogicalConstant(bool value, ttype type)
| LogicalNot(expr arg, ttype type, expr? value)
| LogicalCompare(expr left, cmpop op, expr right, ttype type, expr? value)
- | LogicalBinOp(expr left, logicalbinop op, expr right, ttype type, expr? value)
+ | LogicalBinOp(expr left, logicalbinop op, expr right, logicalevaltype eval_type, ttype type, expr? value)
| ListConstant(expr* args, ttype type)
| ListLen(expr arg, ttype type, expr? value)
@@ -435,6 +435,8 @@ binop = Add | Sub | Mul | Div | Pow | BitAnd | BitOr | BitXor | BitLShift | BitR
logicalbinop = And | Or | Xor | NEqv | Eqv
+logicalevaltype = EvalShortCircuit | EvalEager | EvalUnspecified
+
cmpop = Eq | NotEq | Lt | LtE | Gt | GtE
integerboz = Binary | Hex | Octal Here the Python and C frontends will use All three are different. In terms of what rewriting (optimization) one can do on an expression, all three cases above I think have different semantics. It seems that
Finally, our optimizer can analyze an expression, and if all functions/operands are side-effects-free, then I think If operands are side-effects-free and they do not depend on each other (so NOT this issue), then I think |
This issue still exists. An MRE that fails: % cat examples/expr2.py
from lpython import i32
a: i32 = 10
def hi() -> bool:
global a
a = a + 1
return True
def main0():
if False and hi():
pass
print(a)
assert a == 10
if __name__ == "__main__":
main0()
% python examples/expr2.py
10
% lpython examples/expr2.py
11
AssertionError |
I discovered this when I first ran
and it gave me this error
Looking at the implementation of
_lpython_str_lstrip
I realized that the
and
inwhile ind < len(x) and x[ind] == ' ':
wasn't short circuiting as expected. It becomes more clear when running a minimal exampleThis raises the index out of bounds error, because the second expression is being executed even though the first expression is
False
.Similarly this raises an error as well
The text was updated successfully, but these errors were encountered: