Skip to content

Conversation

@calintat
Copy link
Contributor

@calintat calintat commented Jan 8, 2026

Description

This PR introduces new assertion macros built on top of the overloaded abort added in an earlier PR.

New assert! form

This now supports formatted messages with arguments:

assert!(cond, fmt, arg1, ..., argN)

// expands to
if (cond) {
    ()
} else {
    abort string_utils::format<N>(&fmt, arg1, ..., argN)
}

Example:

let x = 12;
assert!(x < 10, b"Expected x to be less than 10, but got {}", x)

which aborts with message:

Expected x to be less than 10, but got 12

New assert_eq! and assert_ne! macros

These macros mirror the behaviour and ergonomics of Rust’s assert_eq! and assert_ne!, including structured evaluation and rich error messages. There are three forms depending on the number of arguments.

Two arguments

assert_eq!(left, right)

// expands to
match ((left, right)) {
    (_left, _right) => {
        if (_left == _right) {
            ()
        } else {
            abort string::into_bytes(string_utils::format2(<assertion_failed_message>, _left, _right))
        }
    }
}

Three arguments (custom message)

assert_eq!(left, right, message)

// expands to
match ((left, right)) {
    (_left, _right) => {
        if (_left == _right) {
            ()
        } else {
            abort string::into_bytes(string_utils::format3(<assertion_failed_message>, string::utf8(message), _left, _right))
        }
    }
}

More than three arguments (formatted message)

assert_eq!(left, right, fmt, arg1, ..., argN)

// expands to
match ((left, right)) {
    (_left, _right) => {
        if (_left == _right) {
            ()
        } else {
            abort string::into_bytes(string_utils::format3(<assertion_failed_message>, string_utils::format<N>(&fmt, arg1, ..., argN), _left, _right))
        }
    }
}

Assertion failed message format

The assertion failure message format is inspired by Rust and shows both evaluated values:

assertion failed `left == right`
  left: <left>
 right: <right>

It can also include a custom message:

assertion failed `left == right`: <message>
  left: <left>
 right: <right>

How Has This Been Tested?

Added unit tests for all possible forms of assert!, assert_eq!, and assert_ne!.

Key Areas to Review

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Performance improvement
  • Refactoring
  • Dependency update
  • Documentation update
  • Tests

Which Components or Systems Does This Change Impact?

  • Validator Node
  • Full Node (API, Indexer, etc.)
  • Move/Aptos Virtual Machine
  • Aptos Framework
  • Aptos CLI/SDK
  • Developer Infrastructure
  • Move Compiler
  • Other (specify)

Checklist

  • I have read and followed the CONTRIBUTING doc
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I identified and added all stakeholders and component owners affected by this change as reviewers
  • I tested both happy and unhappy path of the functionality
  • I have made corresponding changes to the documentation

Note

Introduces assertion macros with rich messages and compiler support.

  • Implements macro expansion for assert!, assert_eq!, and assert_ne! in move-model/src/builder/macros.rs, generating conditionals/matches and formatted messages via std::string/std::string_utils
  • Extends well-known modules and ensures implicit inclusion of vector, cmp, string, and string_utils during dependency closure; adds helpers for UTF8/bytes conversion
  • Adds string::into_bytes to stdlib string.move
  • Updates tests: new e2e transactional tests (macros.rs, Move package) and numerous compiler/bytecode/typing/naming/macros test expectations; adds a macros test config
  • Minor infra tweaks: decompiler tests exclude vector.move, docgen link adjustments

Written by Cursor Bugbot for commit 965eee0. This will update automatically on new commits. Configure here.

Copy link
Contributor Author

calintat commented Jan 8, 2026

@calintat calintat force-pushed the calin/new-assert-macros branch 16 times, most recently from 6e4ed8d to a43331c Compare January 9, 2026 13:45
@calintat calintat force-pushed the calin/compiler-abort-message branch from 7c56a57 to bfd3c95 Compare January 9, 2026 13:45
@calintat calintat force-pushed the calin/new-assert-macros branch 3 times, most recently from cee2eb9 to 3eae191 Compare January 9, 2026 15:07
@calintat calintat marked this pull request as ready for review January 9, 2026 15:47
@calintat calintat requested review from junxzm1990 and wrwg January 9, 2026 15:47
Base automatically changed from calin/compiler-abort-message to main January 9, 2026 16:53
@calintat calintat force-pushed the calin/new-assert-macros branch from 830781c to 3a838c7 Compare January 9, 2026 17:56
@calintat
Copy link
Contributor Author

calintat commented Jan 9, 2026

Re-drafting this following discussion in standup. Need to enforce the message is a constant.

@calintat calintat marked this pull request as draft January 9, 2026 18:03
@calintat calintat force-pushed the calin/new-assert-macros branch from ef8dfc6 to 01c7eef Compare January 10, 2026 00:44
@calintat calintat marked this pull request as ready for review January 10, 2026 15:32
@calintat calintat force-pushed the calin/new-assert-macros branch from 01c7eef to fbedd91 Compare January 11, 2026 20:55
}

/// Calls a standard library function `std::module_name::function_name(args)`.
fn call_std_function(
Copy link
Contributor

@junxzm1990 junxzm1990 Jan 13, 2026

Choose a reason for hiding this comment

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

It's nice to reuse std functions. I am just a bit worried about dependencies. If the users do not explicitly import string_utils/string, the dependency between the current module and string_utils/string will not be built. In result, the users may see an error message saying that string_utils/string is not bound, creating some confusion.

Maybe you can do some tests using the CLI to compile an exmple with assert_eq! but does not include any dependency in its Move.toml, and see what happens.

We used to face similar problems when dealing with std::vector and std::cmp. Here is a trick we did to avoid such problems:
https://github.com/aptos-labs/aptos-core/pull/16812/files#diff-9b8fbd37b0c05da93fc009674561ea37f0fdc242b021e9ce5300358e717368f2. Meanwhile, we were better positioned to check if the std::cmp module is present as we already have the move model: https://github.com/aptos-labs/aptos-core/pull/16812/files#diff-17c49bd2efe73148cec80384375c0a69d31778daafd97196485318719fdb7a74R184

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe you can do some tests using the CLI to compile an exmple with assert_eq! but does not include any dependency in its Move.toml, and see what happens.

It will give an error message that the function names are not bound, e.g.

error: no function named `string::into_bytes` found
  ┌─ ./sources/test.move:4:9
  │
4 │         assert_eq!(1, 2);
  │         ^^^^^^^^^

error: no function named `string_utils::format2` found
  ┌─ ./sources/test.move:4:9
  │
4 │         assert_eq!(1, 2);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I did a similar trick to what we do for cmp and vector. Now, if you try to use assert_eq! without having either move-stdlib or aptos-stdlib in your dependencies, you’ll get a more helpful error:

error: cannot find `string_utils` module
  ┌─ ./sources/test.move:4:9
  │
9 │         assert_eq!(1, 2);
  │         ^^^^^^^^^

error: cannot find `string` module
  ┌─ ./sources/test.move:4:9
  │
9 │         assert_eq!(1, 2);
  │         ^^^^^^^^^

Copy link
Contributor

Choose a reason for hiding this comment

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

This looks better.

It feels even nicer if we could let users know that they need to incldue move-stdlib as a dependency when using assert with strings, which is, however, not doable here as dependencies may not have been resolved. Maybe we should do an AST rewrite after the movel model is built, but that would be a different implementation.

Anyways, time to move forward.

@calintat calintat force-pushed the calin/new-assert-macros branch from fbedd91 to 5611a6e Compare January 14, 2026 15:52
@calintat calintat force-pushed the calin/new-assert-macros branch from 5611a6e to 4f98ddd Compare January 14, 2026 15:57
@calintat calintat requested a review from junxzm1990 January 14, 2026 16:03
@calintat calintat force-pushed the calin/new-assert-macros branch from b9863b4 to 36fa32c Compare January 14, 2026 20:15
@calintat calintat force-pushed the calin/new-assert-macros branch from 36fa32c to 965eee0 Compare January 15, 2026 15:39
Copy link
Contributor

@wrwg wrwg left a comment

Choose a reason for hiding this comment

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

Nice work!

@calintat calintat requested a review from vineethk January 20, 2026 13:52
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