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

[Feature] [Compiler-V2] += and the like #14583

Merged
merged 60 commits into from
Oct 3, 2024
Merged

Conversation

fEst1ck
Copy link
Contributor

@fEst1ck fEst1ck commented Sep 10, 2024

Description

Introduces operators +=, -=, *=, %=, /=, |=, &=, ^=, <<=, >>=, to Move 2.1.

Implementation

We expand e1 += e2 to

{ let t2 = e2; let t1 = &mut e1; *t1 = *t1 + t2 }

For the special case *e1 += e2, it's expanded to

{ let t2 = e2; let t1 = e1; *t1 = *t1 + e2 }

and for var += e

{ let t = e; var = var + t }

The expansion is done in the expansion phase.

Type of Change

  • New feature

Which Components or Systems Does This Change Impact?

  • Move/Aptos Virtual Machine

How Has This Been Tested?

Tests under third_party/move/move-compiler-v2/tests/plus-equal and third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/plus-equal.

Copy link

trunk-io bot commented Sep 10, 2024

⏱️ 2h 47m total CI duration on this PR
Job Cumulative Duration Recent Runs
rust-move-unit-coverage 16m 🟩
rust-move-unit-coverage 16m 🟩
rust-cargo-deny 15m 🟩🟩🟩🟩 (+2 more)
rust-move-unit-coverage 14m 🟩
general-lints 13m 🟩🟩🟩🟩 (+2 more)
rust-move-unit-coverage 11m 🟩
rust-move-unit-coverage 11m 🟩
rust-move-tests 10m 🟩
rust-move-tests 9m 🟩
rust-move-tests 9m 🟩
rust-move-tests 9m 🟩
rust-move-tests 9m 🟩
check-dynamic-deps 9m 🟩🟩🟩🟩🟩 (+3 more)
semgrep/ci 3m 🟩🟩🟩🟩🟩 (+3 more)
rust-move-unit-coverage 3m
rust-move-tests 2m
file_change_determinator 2m 🟩🟩🟩🟩🟩 (+3 more)
file_change_determinator 2m 🟩🟩🟩🟩🟩 (+3 more)
rust-move-tests 1m
rust-move-unit-coverage 1m
permission-check 36s 🟩🟩🟩🟩🟩 (+3 more)
permission-check 33s 🟩🟩🟩🟩🟩 (+3 more)
permission-check 24s 🟩🟩🟩🟩🟩 (+3 more)
permission-check 21s 🟩🟩🟩🟩🟩 (+3 more)
rust-move-unit-coverage 1s
rust-move-tests 1s

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

Job Duration vs 7d avg Delta
rust-cargo-deny 5m 2m +171%

settingsfeedbackdocs ⋅ learn more about trunk.io

@fEst1ck fEst1ck force-pushed the plus-equal branch 3 times, most recently from c68bb50 to 68d8d04 Compare September 17, 2024 06:35
@fEst1ck fEst1ck marked this pull request as ready for review September 17, 2024 06:48
@fEst1ck fEst1ck marked this pull request as draft September 17, 2024 08:18
@fEst1ck fEst1ck marked this pull request as ready for review September 19, 2024 08:00
@fEst1ck fEst1ck requested a review from vineethk September 19, 2024 08:01
@fEst1ck fEst1ck requested review from brmataptos, wrwg and rahxephon89 and removed request for brmataptos September 19, 2024 08:01
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 may want another variant of LValue for vector indexing.

@brmataptos
Copy link
Contributor

Your top-level description is currently inconsistent. Can you please fix it?

@@ -0,0 +1,166 @@
//# publish
module 0x42::test {
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. The following tests differ in their semantics from (corresponding) Rust. This needs to be investigated and discussed. We need to have a good reason to differ from the Rust semantics in these cases.
// 1
module 0xc0ffee::m {
    public fun test(): u64 {
        let v = 1;
        v += {v += {v += 2; v}; v};
        v
    }
}

// 2
module 0xc0ffee::m {
    public fun test(): u64 {
        let v = 1;
        v += {v += 2; v};
        v
    }
}


// 3
module 0xc0ffee::m {
    fun mod(r: &mut u64) {
        *r += 2;
    }

    public fun test(): u64 {
        let v = 1;
        v += {mod(&mut v); v};
        v
    }
}

// 4
module 0xc0ffee::m {
    fun mod(r: &mut u64): u64 {
        *r += 2;
        *r
    }

    public fun test(): u64 {
        let v = 1;
        v += mod(&mut v);
        v
    }
}
  1. The following test correctly fails to compile, we just need to include it somewhere as a test.
module 0xc0ffee::m {
    struct S has drop {
        x: u64,
    }

    fun foo(self: &mut S): u64 {
        self.x += 1;
        1
    }

    public fun test(): u64 {
        let s = S { x: 0 };
        s.x += s.foo();
        s.x
    }
}
  1. The following test cases have the correct behavior, they just need to be included to showcase no double evaluation of the lhs.
// 1
module 0xc0ffee::m {
    fun foo(r: &mut u64): &mut u64 {
        *r += 1;
        r
    }

    public fun test(): u64 {
        let x = 1;
        *{foo(&mut x)} += 1;
        x
    }
}

// 2
module 0xc0ffee::m {
    fun foo(r: &mut u64) {
        *r += 2;
    }

    public fun test(): u64 {
        let x = 1;
        *{foo(&mut x); foo(&mut x); &mut x} += 1;
        x
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It turns out that in Rust, the RHS of the += operator is evaluated first.

If both types are primitives, then the modifying operand will be evaluated first followed by the assigned operand. It will then set the value of the assigned operand’s place to the value of performing the operation of the operator with the values of the assigned operand and modifying operand.
https://doc.rust-lang.org/reference/expressions/operator-expr.html#compound-assignment-expressions

We are aligned with Rust now. The Rust version of the test is here for convenience

fn test0() -> u64 {
    let mut v = 1;
    v += {
        v += {
            v += 2;
            v
        };
        v
    };
    v
}

fn test1() -> u64 {
    let mut v = 1;
    v += {
        v += 2;
        v
    };
    v
}

fn mod1(r: &mut u64) {
    *r += 2;
}

fn test2() -> u64 {
    let mut v = 1;
    v += {
        mod1(&mut v);
        v
    };
    v
}

fn mod2(r: &mut u64) -> u64 {
    *r += 2;
    *r
}

fn test3() -> u64 {
    let mut v = 1;
    v += mod2(&mut v);
    v
}

fn main() {
    println!("{:?}", test0());
    println!("{:?}", test1());
    println!("{:?}", test2());
    println!("{:?}", test3());
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice.

I saw that you added the tests I posted under bullet point 1, but don't see the tests I suggested in bullet points 2 and 3. If you have already added them, can you point them to me? If not, could you please add them (and point me to them)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bullet point2: third_party/move/move-compiler-v2/tests/op-equal/valid2.exp
It however compiles in the latest commit, because of the change in semantics. The corresponding Rust program also compiles

struct S {
    x: u64,
}

impl S {
    fn foo(self: &mut S) -> u64 {
        self.x += 1;
        1
    }
}

fn test() -> u64 {
    let mut s = S { x: 0 };
    let p = &mut s.x;
    *p = *p + 
    s.x += s.foo();
    s.x
}

Bullet point3: third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/no_double_eval.move

third_party/move/move-model/src/lib.rs Outdated Show resolved Hide resolved
third_party/move/move-compiler/src/parser/syntax.rs Outdated Show resolved Hide resolved
@@ -96,6 +96,29 @@ fn require_move_2(context: &mut Context, loc: Loc, description: &str) -> bool {
}
}

fn require_language_version(
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use this (more general function) instead of the require_move_2, so that we reduce code duplication?

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. This gives different error messages though.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can change all the calls of require_move_2, which is just a specialization of require_language_version, AFAICT (barring the slight difference in error messages). But we can do it in a later PR, no need to do it here.

third_party/move/move-compiler/src/parser/syntax.rs Outdated Show resolved Hide resolved
third_party/move/move-compiler/src/expansion/translate.rs Outdated Show resolved Hide resolved
third_party/move/move-compiler-v2/tests/testsuite.rs Outdated Show resolved Hide resolved
@fEst1ck fEst1ck requested a review from vineethk October 1, 2024 08:51
Copy link
Contributor

Still looks ok, though Vineeth's right that some things could be simplified with a bit more abstraction.

Copy link
Contributor

@vineethk vineethk left a comment

Choose a reason for hiding this comment

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

Looking good to me, just wanted to confirm that we add the tests I suggested (as noted in a comment).

third_party/move/move-model/src/metadata.rs Outdated Show resolved Hide resolved
@@ -96,6 +96,29 @@ fn require_move_2(context: &mut Context, loc: Loc, description: &str) -> bool {
}
}

fn require_language_version(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can change all the calls of require_move_2, which is just a specialization of require_language_version, AFAICT (barring the slight difference in error messages). But we can do it in a later PR, no need to do it here.

@@ -0,0 +1,166 @@
//# publish
module 0x42::test {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice.

I saw that you added the tests I posted under bullet point 1, but don't see the tests I suggested in bullet points 2 and 3. If you have already added them, can you point them to me? If not, could you please add them (and point me to them)?

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.

Copy link
Contributor

github-actions bot commented Oct 3, 2024

✅ Forge suite realistic_env_max_load success on 2cebd2a45120adf7ed140ce42e5abe291ad93a02

two traffics test: inner traffic : committed: 13755.97 txn/s, latency: 2888.82 ms, (p50: 2700 ms, p70: 3000, p90: 3000 ms, p99: 3600 ms), latency samples: 5230320
two traffics test : committed: 99.96 txn/s, latency: 2504.73 ms, (p50: 2400 ms, p70: 2500, p90: 2700 ms, p99: 4800 ms), latency samples: 1740
Latency breakdown for phase 0: ["QsBatchToPos: max: 0.242, avg: 0.221", "QsPosToProposal: max: 0.279, avg: 0.242", "ConsensusProposalToOrdered: max: 0.323, avg: 0.298", "ConsensusOrderedToCommit: max: 0.485, avg: 0.458", "ConsensusProposalToCommit: max: 0.781, avg: 0.756"]
Max non-epoch-change gap was: 0 rounds at version 0 (avg 0.00) [limit 4], 0.80s no progress at version 2331676 (avg 0.21s) [limit 15].
Max epoch-change gap was: 0 rounds at version 0 (avg 0.00) [limit 4], 8.50s no progress at version 2331674 (avg 8.50s) [limit 15].
Test Ok

Copy link
Contributor

github-actions bot commented Oct 3, 2024

✅ Forge suite framework_upgrade success on e8a6faf60a98afca8982e0582f929401294bbd33 ==> 2cebd2a45120adf7ed140ce42e5abe291ad93a02

Compatibility test results for e8a6faf60a98afca8982e0582f929401294bbd33 ==> 2cebd2a45120adf7ed140ce42e5abe291ad93a02 (PR)
Upgrade the nodes to version: 2cebd2a45120adf7ed140ce42e5abe291ad93a02
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 962.05 txn/s, submitted: 963.62 txn/s, failed submission: 1.57 txn/s, expired: 1.57 txn/s, latency: 3284.59 ms, (p50: 2100 ms, p70: 4200, p90: 7200 ms, p99: 9200 ms), latency samples: 85880
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 875.52 txn/s, submitted: 877.33 txn/s, failed submission: 1.81 txn/s, expired: 1.81 txn/s, latency: 3473.60 ms, (p50: 2400 ms, p70: 4000, p90: 7600 ms, p99: 9900 ms), latency samples: 77540
5. check swarm health
Compatibility test for e8a6faf60a98afca8982e0582f929401294bbd33 ==> 2cebd2a45120adf7ed140ce42e5abe291ad93a02 passed
Upgrade the remaining nodes to version: 2cebd2a45120adf7ed140ce42e5abe291ad93a02
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 904.24 txn/s, submitted: 905.33 txn/s, failed submission: 1.10 txn/s, expired: 1.10 txn/s, latency: 3175.88 ms, (p50: 2400 ms, p70: 3400, p90: 6700 ms, p99: 8100 ms), latency samples: 82500
Test Ok

Copy link
Contributor

github-actions bot commented Oct 3, 2024

✅ Forge suite compat success on e8a6faf60a98afca8982e0582f929401294bbd33 ==> 2cebd2a45120adf7ed140ce42e5abe291ad93a02

Compatibility test results for e8a6faf60a98afca8982e0582f929401294bbd33 ==> 2cebd2a45120adf7ed140ce42e5abe291ad93a02 (PR)
1. Check liveness of validators at old version: e8a6faf60a98afca8982e0582f929401294bbd33
compatibility::simple-validator-upgrade::liveness-check : committed: 12234.45 txn/s, latency: 2806.25 ms, (p50: 1900 ms, p70: 2200, p90: 3600 ms, p99: 22700 ms), latency samples: 460540
2. Upgrading first Validator to new version: 2cebd2a45120adf7ed140ce42e5abe291ad93a02
compatibility::simple-validator-upgrade::single-validator-upgrading : committed: 7296.80 txn/s, latency: 3908.35 ms, (p50: 4300 ms, p70: 4700, p90: 4800 ms, p99: 4900 ms), latency samples: 137680
compatibility::simple-validator-upgrade::single-validator-upgrade : committed: 6325.83 txn/s, latency: 4756.69 ms, (p50: 5000 ms, p70: 5300, p90: 5400 ms, p99: 6200 ms), latency samples: 238980
3. Upgrading rest of first batch to new version: 2cebd2a45120adf7ed140ce42e5abe291ad93a02
compatibility::simple-validator-upgrade::half-validator-upgrading : committed: 6027.00 txn/s, latency: 4570.63 ms, (p50: 5000 ms, p70: 5400, p90: 6200 ms, p99: 6400 ms), latency samples: 116000
compatibility::simple-validator-upgrade::half-validator-upgrade : committed: 6519.30 txn/s, latency: 4932.34 ms, (p50: 5200 ms, p70: 5400, p90: 6900 ms, p99: 7200 ms), latency samples: 216220
4. upgrading second batch to new version: 2cebd2a45120adf7ed140ce42e5abe291ad93a02
compatibility::simple-validator-upgrade::rest-validator-upgrading : committed: 203.87 txn/s, submitted: 406.53 txn/s, failed submission: 202.65 txn/s, expired: 202.65 txn/s, latency: 46774.95 ms, (p50: 46700 ms, p70: 47400, p90: 48000 ms, p99: 48000 ms), latency samples: 20060
compatibility::simple-validator-upgrade::rest-validator-upgrade : committed: 8100.84 txn/s, latency: 3801.43 ms, (p50: 3600 ms, p70: 4300, p90: 5100 ms, p99: 5500 ms), latency samples: 271040
5. check swarm health
Compatibility test for e8a6faf60a98afca8982e0582f929401294bbd33 ==> 2cebd2a45120adf7ed140ce42e5abe291ad93a02 passed
Test Ok

@fEst1ck fEst1ck merged commit 9271edf into aptos-labs:main Oct 3, 2024
50 checks passed
fEst1ck added a commit to aptos-labs/developer-docs that referenced this pull request Oct 9, 2024
### Description

Add documentation for the op equals aptos-labs/aptos-core#14583.

### Checklist

- Do all Lints pass?
  - [x] Have you ran `pnpm spellcheck`?
  - [x] Have you ran `pnpm fmt`?
  - [x] Have you ran `pnpm lint`?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants