-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[compiler-v2][lint] Complex boolean expression checker #16721
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
base: main
Are you sure you want to change the base?
[compiler-v2][lint] Complex boolean expression checker #16721
Conversation
third_party/move/tools/move-linter/tests/model_ast_lints/simplifiable_boolean_expression.move
Outdated
Show resolved
Hide resolved
third_party/move/tools/move-linter/tests/model_ast_lints/simplifiable_boolean_expression.move
Outdated
Show resolved
Hide resolved
third_party/move/tools/move-linter/src/model_ast_lints/simplifiable_boolean_expression.rs
Outdated
Show resolved
Hide resolved
@vineethk PTAL |
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.
Looking generally good, please address the new comments.
third_party/move/tools/move-linter/src/model_ast_lints/simpler_bool_expression.rs
Outdated
Show resolved
Hide resolved
(ExpData::LocalVar(_, s1), ExpData::LocalVar(_, s2)) => s1 == s2, | ||
(ExpData::Value(_, v1), ExpData::Value(_, v2)) => v1 == v2, | ||
(ExpData::Temporary(_, t1), ExpData::Temporary(_, t2)) => t1 == t2, | ||
(ExpData::Call(_, op1, args1), ExpData::Call(_, op2, args2)) => { |
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.
This is not true if the operation can be side-effecting (which means calling it twice is different from calling it once). We should assume that all user-defined functions are side-effecting.
You may be able to use Operation::is_ok_to_remove_from_code
to approximate your usage here (but please verify and double check carefully what that function does, and add corresponding test cases).
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.
The idea is to use operation.is_ok_to_remove_from_code()
? I could modify it to fit this scenario, but I'm not sure this would work since functions like the following still trigger the lint, even though helper_function()
could be side-effecting. This function (is_ok_to_remove_from_code
) seems to be defined for ExpData
too, but it still triggers the lint..
public fun test_distributive_law_mixed() {
let x = helper_function();
let y = 5;
if ((x && TRUE_CONST) || (x && (y > 10))) ();
if ((x || FALSE_CONST) && (x || (y > 10))) ();
}
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.
When you have:
let x = helper_function();
x && x && x;
x
is only evaluated once (so it does not matter if it is side-effecting), as opposed to:
helper_function() && helper_function() && helper_function()
.
Please check whether the function suggested is appropriate (if not, do not use it): you may want to only disallow user defined functions here.
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.
done.
I have added checks on is_expression_equal
to ignore operations of type MoveFunction
on the expressions itself or any of the arguments. Let me know if that covers it. I could add some sort of logic to check wether it was only used once, I'm not sure this adds value to the end user though, right now if a user defined function is used, the check gets ignored.
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.
There are other Operation
which can return different results or carry side effects when Called twice, e.g., Closure
and MoveFrom
.
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 point, we need to consider some of the other things that can be side-effecting as well!
- I think we also need to handle
Invoke
(similar toCall
, but instead of a fixed entity to call, it can call whatever an expression evaluates to). This needs tests. - Not completely sure if we need to include
MoveFrom
(or evenClosure
) etc in these contexts. For example, it is an error to move from a global value twice, and the lint can assume that. Either way, looks like we need some tests to showcase these.
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.
Nevermind, Invoke
is already handled (I was confusing it with the stackless bytecode's Invoke
).
Might still be worth it to think through each Operation
and add some tests (e.g., (|| true)() && (|| true)
.
On the other hand, it might be easier to allow specific Operation
s (write a function that matches over Operation
and returns true
or false
on whether it is appropriate for consideration here, in this way we only explicitly allow stuff we want to, rather than inadvertently allow something). It is okay to have some false negatives (we always will) instead of false positives (which we should strive to minimize).
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.
Yeah, calling MoveFrom
twice with the same arg will be an error, but I felt we might consider detecting that separately. Otherwise, the user will see a suggestion like MoveFrom<ty1>(addr1) && MoveFrom<ty1>(addr1) can be simplified to MoveFrom<ty1>(addr1)
.
I am concerned about Closure
because it can call MoveFunction
inside.
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.
Yeah, reasonable point about MoveFrom
: I don't remember whether we err out by the time we reach the lint phase for this or not - a test case would tell.
Note: Closure
cannot "call" MoveFunction
inside: it only "creates" the closure. It is Invoke
that calls the closure, which in turn calls the function inside (the terms referred to here are all the model AST terms, to remove ambiguity).
Given all these discussions, I am more of the opinion that we should have a function that matches over various Operation
that true
or false
on whether such operations should participate in the structural equality.
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.
oh, good to learn about Closure
v.s. Invoke
! Yes, I would also support a match over various Operation
. Something like is_ok_to_remove_from_code
but less restrictive.
third_party/move/tools/move-linter/tests/model_ast_lints/simpler_bool_expression.exp
Outdated
Show resolved
Hide resolved
third_party/move/tools/move-linter/tests/model_ast_lints/simpler_bool_expression.exp
Outdated
Show resolved
Hide resolved
third_party/move/tools/move-linter/tests/model_ast_lints/simpler_bool_expression.move
Show resolved
Hide resolved
third_party/move/tools/move-linter/src/model_ast_lints/simpler_bool_expression.rs
Show resolved
Hide resolved
@vineethk PTAL |
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.
Please post results of running on certain projects like aptos-framework.
third_party/move/tools/move-linter/tests/model_ast_lints/simpler_bool_expression.move
Show resolved
Hide resolved
Results of running the compiled linter on:
-> This new lint |
@vineethk PTAL |
third_party/move/tools/move-linter/tests/model_ast_lints/simpler_bool_expression.move
Outdated
Show resolved
Hide resolved
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
❌ Forge suite
|
This comment has been minimized.
This comment has been minimized.
5b328b2
to
2d4b191
Compare
2d4b191
to
f40a908
Compare
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.
Looks good to me!
bee3c80
to
d80ea2a
Compare
This comment has been minimized.
This comment has been minimized.
✅ Forge suite
|
Head branch was pushed to by a user without write access
… are known constants. Only evaluate side-effect free equality on expressions (remove `move-functions`)
…er_bool_expression.move Co-authored-by: Vineeth Kashyap <[email protected]>
dd52118
to
0034d08
Compare
Description
This PR introduces a new lint detector for the move-linter:
simplifiable_boolean_expression
. This detector identifies overly complex boolean expressions that can be simplified using fundamental boolean algebra laws.Supported Simplification Patterns:
Absorption Laws:
Idempotence Laws:
Contradiction Laws:
Tautology Laws:
Distributive Laws:
The detector analyzes boolean expressions in Move code and suggests simplified equivalents.
How Has This Been Tested?
aptos-move/framework/*
Key Areas to Review
check_absorption_law
: Detects when OR expressions contain redundant AND sub-expressionscheck_idempotence
: Identifies duplicate operands in AND/OR expressionscheck_contradiction_tautology
: Finds expressions with negated operandscheck_distributive_law
: Complex pattern matching for distributive simplificationsis_expression_equal
: This method handles structural comparison of AST nodes by value/symbolSimplifiablePattern
to handle suggestions.Type of Change
Which Components or Systems Does This Change Impact?