-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
[Compiler-V2] Check Unused Assignments #13543
Conversation
⏱️ 6h 15m total CI duration on this PR
🚨 2 jobs on the last run were significantly faster/slower than expected
|
warning: Unused assignment to `w`. Consider removing or prefixing with an underscore: `_w` | ||
┌─ tests/unused-assignment/unused_assignment.move:7:17 | ||
│ | ||
7 │ let w = bar(false); |
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 location here is wrong because this is generated at see line 123
5: $t5 := test::bar($t6)
# live vars:
where $t5
is assigned but not used later. However, the location of this instruction has location bar(false)
which is the RHS of the original assignment let w = bar(false);
.
This perhaps can be solved by my previous PR which adds location for the arguments of the stackless bytecode. When we do this check, we haven't done any transformations.
warning: Unused local variable `y`. Consider removing or prefixing with an underscore: `_y` | ||
┌─ tests/unused-assignment/unused_assignment.move:5:13 | ||
│ | ||
5 │ let y = 0; |
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.
Note that this warning is generated by @brianrmurphy 's flow_insensitive_checker
, and NOT by our checker. Upon looking at the generated bytecode below, I believe this assignment has been optimized out on the AST level, and so we can't see it in the bytecode 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.
We need more tests. We can have unused assignments through pattern destructuring, unused assignment in a branch that is later never used, assignment in branch that is later used, unused assignment to parameters (parameters and locals are handled a bit differently, so this is always good to test) etc.
One rich source of tests is the following. Search for "unused assignment" in all *.exp files. You will find several test cases in the old compiler that should all be ported over, and the testdiff tool should updated, update_v1_diff.sh
should be run to update the test diff files showing these tests being ported.
id: AttrId, | ||
offset: CodeOffset, | ||
dst: TempIndex, | ||
after: bool, |
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.
Why do we need after
? All uses of this method seem to pass true
to this parameter.
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. (A previous commit used this when checking for unused parameters.)
) { | ||
let data = target.data; | ||
// only check for user defined variables | ||
if let Some(dst_name) = data.local_names.get(&dst) { |
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.
Does this include parameters to a function? Can you please include a test that has unused assignment to a parameter?
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.
Yes. Done.
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.
Which test is it? I seem to not be able to find such a test.
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.
Any answer?
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.
Sorry, I missed this comment. See for example third_party/move/move-compiler-v2/tests/unused-assignment/unused_call_assign_shadow.exp
. The flow-insensitive checker warns unused parameters; the unused assignment checker does NOT warn them, because the parameters are always inferred to be alive before the first instruction by the current analysis, even if they are not used anywhere at all.
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.
@fEst1ck I still don't see it, and maybe I was not clear about what I was asking, I have tried to make it concrete below:
We need to have a function foo
with a parameter x
. We then assign a value to x
in the function foo
. After this assignment, there should be no read of x
(thus, there is an unused assignment to a parameter). I do not think the test case you point to (or others, at the time I inspected them) has a similar case.
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.
@vineethk Thanks for the clarification. I added a new test third_party/move/move-compiler-v2/tests/unused-assignment/unused_assign_to_param.move
for this.
let dst_name = dst_name.display(target.func_env.symbol_pool()).to_string(); | ||
if !dst_name.starts_with('_') && live_var_info.get(&dst).is_none() { | ||
let loc = target.get_bytecode_loc(id); | ||
target.global_env().diag(Severity::Warning, &loc, &format!("Unused assignment to `{}`. Consider removing or prefixing with an underscore: `_{}`", dst_name, dst_name)); |
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.
Seems like an unusually long line, maybe rustfmt did not break it up conservatively because of the string involved?
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.
Manually edited.
.set_experiment(Experiment::UNUSED_ASSIGNMENT_CHECK, true), | ||
stop_after: StopAfter::BytecodePipeline(Some("UnusedAssignmentChecker")), | ||
dump_ast: DumpLevel::None, | ||
dump_bytecode: DumpLevel::EndStage, |
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.
Do we need the bytecode to be dumped for these tests? It seems like a distraction from reviewing the warnings.
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. Was using it for debugging.
89f28ab
to
a01899e
Compare
@vineethk Thanks for the comments! All addressed now. |
@wrwg We cannot remove @brianrmurphy 's check implemented in |
|
||
|
||
Diagnostics: | ||
warning: Unused assignment to `r`. Consider removing or prefixing with an underscore: `_r` |
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.
Hmm. Looks like we are duplicating warnings (although they are of different "types", to a user, they are very similar). What does v1 do in these cases? IMO, we should not have a unused assignment warning if for the same location we have already provided unused variable warning.
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 should be avoided, but the solution is probably not trivial.
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.
Submitted issue #13744 tracking this.
@fEst1ck I can't seem to find tests that have unused assignments through pattern destructuring ( |
done |
See the following tests from move-compiler:
|
d097ebc
to
5d5d645
Compare
Imported in V2. |
All comments addressed. PTAL @vineethk @brmataptos |
|
||
public fun mixed() { | ||
let r = 0; | ||
let r_ref = &mut r; |
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.
Should have unused assignment
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 is an "invalid assignment" warning in the front end, so we never reach the phase of unused assignment checking here.
public fun mixed() { | ||
let r = 0; | ||
let r_ref = &mut r; | ||
let s = S { f: 0 }; |
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.
unused assignment here, too.
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.
same
) { | ||
let data = target.data; | ||
// only check for user defined variables | ||
if let Some(dst_name) = data.local_names.get(&dst) { |
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.
Any answer?
if !dst_name.starts_with('_') && live_after.get(&dst).is_none() { | ||
let loc = target.get_bytecode_loc(id); | ||
target | ||
.global_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.
no tab characters, please.
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
@@ -71,6 +71,50 @@ fun m::f($t0: u8, $t1: &vector<u64>): u64 { | |||
14: return $t2 | |||
} | |||
|
|||
============ after LiveVarAnalysisProcessor: ================ |
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.
Why are we printing debugging info in test outputs?
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's the original test configuration for the ability transformer. We have this new debugging info since we run one more live var analysis.
@@ -42,6 +42,14 @@ public fun m::test(): u8 { | |||
} | |||
|
|||
|
|||
Diagnostics: | |||
warning: Unused assignment to `q`. Consider removing or prefixing with an underscore: `_q` |
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 warning is redundant. We could suppress in the case of no uses, in favor of "unused variable". But it's simpler to remove the declaration when the "unused variable" warning is generated. Filed #13791 to track that.
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 explored removing the unused declaration back in the AST and it's pretty messy. Would be simpler to suppress the redundant warning here in the case of a variable declaration. Perhaps that will require a change to the bytecode to track whether an assignment/loc corresponds to a variable declaration.
All comments addressed. PTAL @brmataptos I missed your comments on the test for unused function parameters. Please see the reply above @vineethk |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ Forge suite
|
✅ Forge suite
|
✅ Forge suite
|
Description
Implements a stackless bytecode pipeline checking for unused assignments and giving warnings to the user.
Addresses #11710.
Type of Change
Which Components or Systems Does This Change Impact?
How Has This Been Tested?