Skip to content
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] Externalize the linter architecture #15138

Merged
merged 1 commit into from
Nov 5, 2024

Conversation

vineethk
Copy link
Contributor

@vineethk vineethk commented Oct 31, 2024

Description

The goal of this PR is to make the compiler v2 accept an option to run externally provided lint checks. The compiler provides necessary traits for external implementors of the lint checks (on AST and stackless bytecode).

Further, all the lint checks inside the compiler are now moved out to a new (third-party) crate called move-linter, which is expected to contain aptos move specific lint checks. The corresponding tests have also been moved.

The aptos CLI lint tool (aptos move lint) invokes the compiler v2 with the checks inside move-linter crate: thus, the existing behavior is unchanged. In the future, it could implement some of the extended checks and even additional checks (such as those particular to aptos framework and ecosystem) and pass along those checks as well, in addition to the checks in move-linter.

A follow up PR will introduce lint.toml to be able to configure the linter, which would be passed to the linter factory making up the lint check instances.

Other implementation options considered

  • Making the external checks part of various configs/options like CompilerConfig, BuildOptions etc. to further minimize API changes. However, this requires implementing serialization/deserialization, PartialEq and other traits for dynamic trait objects.
  • Replicating the build behavior (dependency resolution, compiler driver, etc) for including external checks - this results in a lot of code duplication, which could hamper package system revamping.

After attempting both these options, I settled on changing a handful of APIs (only those needed, we could expand to more on a need basis) to explicitly pass external checks where necessary.

How Has This Been Tested?

  • Existing tests (lint related checks moved from compiler v2 to move-linter crate)
  • Manually tested the aptos move lint CLI command.

Generally speaking, none of the user-visible behavior should have changed from this PR.

Type of Change

  • Refactoring

Which Components or Systems Does This Change Impact?

  • Aptos CLI/SDK
  • Move Compiler

Copy link

trunk-io bot commented Oct 31, 2024

⏱️ 1h 4m total CI duration on this PR
Slowest 15 Jobs Cumulative Duration Recent Runs
execution-performance / single-node-performance 24m 🟩
rust-move-tests 8m 🟩
rust-doc-tests 5m 🟩
test-target-determinator 5m 🟩
execution-performance / test-target-determinator 4m 🟩
rust-cargo-deny 4m 🟩
check 4m 🟩
check-dynamic-deps 3m 🟩🟩
rust-move-tests 2m
fetch-last-released-docker-image-tag 2m 🟩
general-lints 1m 🟩🟩
semgrep/ci 54s 🟩🟩
file_change_determinator 27s 🟩🟩
permission-check 18s 🟩🟩🟩🟩🟩 (+1 more)
permission-check 17s 🟩🟩🟩🟩🟩 (+1 more)

🚨 1 job on the last run was significantly faster/slower than expected

Job Duration vs 7d avg Delta
execution-performance / single-node-performance 24m 17m +40%

settingsfeedbackdocs ⋅ learn more about trunk.io

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @vineethk and the rest of your teammates on Graphite Graphite

@vineethk vineethk force-pushed the vk/linter-externalize branch 2 times, most recently from 8c7392f to ea90b83 Compare October 31, 2024 15:03
@vineethk vineethk changed the title Externalize the linter architecture [compiler-v2] Externalize the linter architecture Oct 31, 2024
@vineethk vineethk marked this pull request as ready for review October 31, 2024 15:31
@vineethk vineethk requested review from rahxephon89, fEst1ck and brmataptos and removed request for davidiw, gregnazario, banool and movekevin October 31, 2024 15:32
Copy link
Contributor

@rahxephon89 rahxephon89 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just left a minor comment

fn visit_expr_post(&mut self, _env: &GlobalEnv, _expr: &ExpData) {}

/// Report the `msg` highlighting the `loc`.
fn report(&self, env: &GlobalEnv, loc: &Loc, msg: &str) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it is an overkill but method get_name and report are common among ExpChecker and StacklessBytecodeChecker, I am wondering whether it is worth to extract them into a super trait?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might even use a single trait with all functions and just stub out the ones that aren't useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. If we extract get_name() into a super trait, then each lint would have to implement two traits (either the exp checker or stackless bytecode checker, and then this trait with get_name). I feel like this is currently an overkill, but can be revisited as these traits evolve to support more functionality.
  2. Implementors of these two traits are called in different places, e.g., each expression as we are visiting them for exp checkers, and each function for stackless bytecode checkers. Putting them together conflates two different concepts, IMO.

Copy link
Contributor

@brmataptos brmataptos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable, see a few minor comments.

212 │ *&mut u
│ ^^^^^^^
= To suppress this warning, annotate the function/module with the attribute `#[lint::skip(needless_deref_ref)]`.


Diagnostics:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we're suppressing all normal compiler warnings here? What about a compiler error?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, please add a test to show what happens with different kinds of compiler errors (parser, type-check).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we are not suppressing all normal compiler warnings here. This warning just ended up moving elsewhere in the expected file, but is still present. The difference is due to the way compiler-v2's testsuite prints out warnings vs how the compiler API prints out the warnings (the lint crate uses the compiler API).

There are already some tests with compiler errors here: e.g., third_party/move/tools/move-linter/tests/model_ast_lints/bad_lint_attribute_01.exp.

@@ -112,7 +113,7 @@ impl CliCommand<&'static str> for LintPackage {

async fn execute(self) -> CliTypedResult<&'static str> {
let move_options = MovePackageDir {
compiler_version: Some(CompilerVersion::V2_0),
compiler_version: Some(CompilerVersion::latest_stable()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, but we maybe should have a separate PR to fix these.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is always good to fix code on the fly, specifically such trivialities.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because the problem may be more widespread. Unless you have time to go fix all the use cases, you've just swept one case under the rug. If you do this, do a thorough search or file an issue to follow up and do it.

You also will have a commit message that says this line was changed to "Externalize the linter architecture". Is that useful for future devs? No.

SWE is communication, not just twiddling dials to make it work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this PR, keeping this change.

Will follow up with another PR that does a more wide-spread fix across the code base.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I filed an issues #15178 to track this.

.get_exp_checkers()
.into_iter()
.map(|c| c.get_name())
.collect::<Vec<_>>()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an efficiency hack? You can actually apply .join(", ") directly to the iterator, though I think I've seen some recommendation that collecting into a vector first is actually faster.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot apply .join(", ") directly to the iterator.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fn visit_expr_post(&mut self, _env: &GlobalEnv, _expr: &ExpData) {}

/// Report the `msg` highlighting the `loc`.
fn report(&self, env: &GlobalEnv, loc: &Loc, msg: &str) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might even use a single trait with all functions and just stub out the ones that aren't useful.

.and_then(|bp| bp.compile_no_exit(&compiler_config.clone(), &mut Vec::new()))
{
(true, _) => match BuildPlan::create(resolved_package).and_then(|bp| {
bp.compile_no_exit(&compiler_config.clone(), vec![], &mut Vec::new())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The juxtaposition of two different ways to create an empty vector is kind of odd. How about

.., vec![], &mut vec![])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@vineethk vineethk force-pushed the vk/linter-externalize branch from ea90b83 to b9b5b53 Compare November 5, 2024 16:13
@vineethk vineethk force-pushed the vk/linter-externalize branch from b9b5b53 to fa4e527 Compare November 5, 2024 16:23
@vineethk vineethk enabled auto-merge (squash) November 5, 2024 16:25

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

Copy link
Contributor

github-actions bot commented Nov 5, 2024

✅ Forge suite realistic_env_max_load success on fa4e527816e47f9699cdb269db99f7dc25ed604b

two traffics test: inner traffic : committed: 14371.55 txn/s, latency: 2764.79 ms, (p50: 2700 ms, p70: 2700, p90: 3000 ms, p99: 3200 ms), latency samples: 5464420
two traffics test : committed: 100.10 txn/s, latency: 1452.90 ms, (p50: 1400 ms, p70: 1500, p90: 1600 ms, p99: 2100 ms), latency samples: 1720
Latency breakdown for phase 0: ["MempoolToBlockCreation: max: 1.982, avg: 1.552", "ConsensusProposalToOrdered: max: 0.314, avg: 0.293", "ConsensusOrderedToCommit: max: 0.376, avg: 0.366", "ConsensusProposalToCommit: max: 0.669, avg: 0.659"]
Max non-epoch-change gap was: 0 rounds at version 0 (avg 0.00) [limit 4], 0.84s no progress at version 2854224 (avg 0.20s) [limit 15].
Max epoch-change gap was: 0 rounds at version 0 (avg 0.00) [limit 4], 8.67s no progress at version 2854222 (avg 8.67s) [limit 15].
Test Ok

Copy link
Contributor

github-actions bot commented Nov 5, 2024

✅ Forge suite framework_upgrade success on 1086a5e00d773704731ab84fb4ed3538613b2250 ==> fa4e527816e47f9699cdb269db99f7dc25ed604b

Compatibility test results for 1086a5e00d773704731ab84fb4ed3538613b2250 ==> fa4e527816e47f9699cdb269db99f7dc25ed604b (PR)
Upgrade the nodes to version: fa4e527816e47f9699cdb269db99f7dc25ed604b
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 1328.25 txn/s, submitted: 1332.30 txn/s, failed submission: 4.06 txn/s, expired: 4.06 txn/s, latency: 2383.11 ms, (p50: 2100 ms, p70: 2400, p90: 3900 ms, p99: 4800 ms), latency samples: 117920
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 1283.36 txn/s, submitted: 1285.59 txn/s, failed submission: 2.23 txn/s, expired: 2.23 txn/s, latency: 2370.56 ms, (p50: 2100 ms, p70: 2700, p90: 3900 ms, p99: 5300 ms), latency samples: 115100
5. check swarm health
Compatibility test for 1086a5e00d773704731ab84fb4ed3538613b2250 ==> fa4e527816e47f9699cdb269db99f7dc25ed604b passed
Upgrade the remaining nodes to version: fa4e527816e47f9699cdb269db99f7dc25ed604b
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 1431.07 txn/s, submitted: 1434.08 txn/s, failed submission: 3.02 txn/s, expired: 3.02 txn/s, latency: 2203.30 ms, (p50: 2100 ms, p70: 2400, p90: 3400 ms, p99: 4900 ms), latency samples: 123260
Test Ok

Copy link
Contributor

github-actions bot commented Nov 5, 2024

✅ Forge suite compat success on 1086a5e00d773704731ab84fb4ed3538613b2250 ==> fa4e527816e47f9699cdb269db99f7dc25ed604b

Compatibility test results for 1086a5e00d773704731ab84fb4ed3538613b2250 ==> fa4e527816e47f9699cdb269db99f7dc25ed604b (PR)
1. Check liveness of validators at old version: 1086a5e00d773704731ab84fb4ed3538613b2250
compatibility::simple-validator-upgrade::liveness-check : committed: 14457.08 txn/s, latency: 2301.38 ms, (p50: 2000 ms, p70: 2100, p90: 2400 ms, p99: 6700 ms), latency samples: 467720
2. Upgrading first Validator to new version: fa4e527816e47f9699cdb269db99f7dc25ed604b
compatibility::simple-validator-upgrade::single-validator-upgrading : committed: 6319.32 txn/s, latency: 4348.75 ms, (p50: 4800 ms, p70: 5100, p90: 5200 ms, p99: 5900 ms), latency samples: 127920
compatibility::simple-validator-upgrade::single-validator-upgrade : committed: 6754.51 txn/s, latency: 4780.33 ms, (p50: 5100 ms, p70: 5300, p90: 6500 ms, p99: 6900 ms), latency samples: 229900
3. Upgrading rest of first batch to new version: fa4e527816e47f9699cdb269db99f7dc25ed604b
compatibility::simple-validator-upgrade::half-validator-upgrading : committed: 6179.12 txn/s, latency: 4336.28 ms, (p50: 4900 ms, p70: 5300, p90: 5300 ms, p99: 5400 ms), latency samples: 122880
compatibility::simple-validator-upgrade::half-validator-upgrade : committed: 6414.64 txn/s, latency: 4922.80 ms, (p50: 5300 ms, p70: 5400, p90: 6700 ms, p99: 7100 ms), latency samples: 214180
4. upgrading second batch to new version: fa4e527816e47f9699cdb269db99f7dc25ed604b
compatibility::simple-validator-upgrade::rest-validator-upgrading : committed: 9014.54 txn/s, latency: 3110.87 ms, (p50: 3000 ms, p70: 3500, p90: 4500 ms, p99: 4600 ms), latency samples: 163800
compatibility::simple-validator-upgrade::rest-validator-upgrade : committed: 9026.24 txn/s, latency: 3568.40 ms, (p50: 3400 ms, p70: 4300, p90: 4900 ms, p99: 5200 ms), latency samples: 298200
5. check swarm health
Compatibility test for 1086a5e00d773704731ab84fb4ed3538613b2250 ==> fa4e527816e47f9699cdb269db99f7dc25ed604b passed
Test Ok

@vineethk vineethk merged commit 277d1ae into main Nov 5, 2024
87 of 92 checks passed
@vineethk vineethk deleted the vk/linter-externalize branch November 5, 2024 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants