[mono-move] String natives#20163
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Implement the remaining string natives for mono-move: internal_is_char_boundary, internal_sub_string, and internal_index_of, mirroring the legacy VM so both produce identical results. Add a differential test (renamed from check_utf8.move to string.move) exercising the new natives through the public string wrappers index_of and sub_string. is_char_boundary has no standalone wrapper, so it is covered through sub_string's boundary asserts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59f9447 to
cb376f6
Compare
4bbf50b to
ed7b4ce
Compare
mono-move benchmark gate2 regression(s) beyond ±3% noise band
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ed7b4ce. Configure here.
| // | ||
| // "héllo" is the six-byte sequence [0x68, 0xc3, 0xa9, 0x6c, 0x6c, 0x6f]: 'h', | ||
| // then 'é' (two bytes 0xc3 0xa9), then "llo". Byte indices 0, 1, 3, 4, 5, 6 are | ||
| // char boundaries; 2 (the 'é' continuation byte) is not. |
There was a problem hiding this comment.
Verbose multi-line header block in test file
Low Severity
The 10-line header block narrates which natives are tested, how they're exercised (through wrappers), and provides byte-level encoding details for "héllo." Per the MonoMove review convention, verbose multi-line header blocks in test files narrating what tests exercise are flagged — brief per-function comments suffice. The per-function comments already present in the file (e.g., // Returns the index of the first occurrence.) are fine.
Triggered by learned rule: MonoMove: flag verbose AI-generated comments in test and code files
Reviewed by Cursor Bugbot for commit ed7b4ce. Configure here.
| // SAFETY: the bytes are consumed immediately, into an owned `Vec`, | ||
| // before any allocation. | ||
| let bytes = unsafe { v.as_bytes() }; | ||
| from_utf8_checked(bytes)?[i..j].as_bytes().to_vec() |
There was a problem hiding this comment.
Are we safely checking if i and j are char boundaries here?
|
|
||
| /// `0x1::string::internal_index_of(v: &vector<u8>, r: &vector<u8>): u64` | ||
| /// | ||
| /// Returns the byte index of the first occurrence of `r` in `v`, or `v.len()` |



Description
Implements the remaining
0x1::stringnatives for mono-move (the v2 VM). Onlyinternal_check_utf8was implemented before; this adds the other three so Move code that callsstring::sub_stringandstring::index_ofcan run:internal_is_char_boundary(v: &vector<u8>, i: u64): boolinternal_sub_string(v: &vector<u8>, i: u64, j: u64): vector<u8>internal_index_of(v: &vector<u8>, r: &vector<u8>): u64Each native mirrors the legacy VM logic so both VMs produce identical results.
internal_sub_stringcopies the result off the VM heap before allocating the return vector, sincenew_byte_vectorcan trigger a GC that relocates the source bytes.How Has This Been Tested?
Renamed the existing
check_utf8.movedifferential test tostring.moveand added cases for the new natives, run on both the legacy MoveVM and mono-move with their outputs compared:index_of: match found, first of multiple occurrences, no match (returns length), empty needle, multibyte content.sub_string: basic ranges, empty range, full string, out-of-range and reversed indices (abort), multibyte boundary success.is_char_boundaryhas no public wrapper, so it is exercised throughsub_string's boundary asserts: the multibyte success cases require it to return true, the mid-codepoint cases require false (abort).All 193 differential cases pass.
Key Areas to Review
arg(0),arg(1),arg(2)).Vecbeforenew_byte_vector.string::insertis not covered end-to-end: it callsvector::append, which needs the0x1::vector::move_rangenative that mono-move does not implement yet. That is out of scope here, andis_char_boundaryis fully covered throughsub_stringinstead.Type of Change
Which Components or Systems Does This Change Impact?
Checklist
Note
Medium Risk
Changes VM string execution and GC-sensitive native code; behavior is constrained by differential tests against the legacy VM but substring/index logic is user-visible on-chain.
Overview
Adds three mono-move natives for
0x1::stringsostring::index_ofandstring::sub_stringwork in the v2 VM alongside the existinginternal_check_utf8. New implementations areinternal_is_char_boundary,internal_sub_string, andinternal_index_of, registered inmake_all_string_natives.Shared
from_utf8_checkedtreats invalid UTF-8 on already-constructed strings as a VM invariant violation.internal_sub_stringaborts with code 1 whenj < i; out-of-range and non-boundary indices are still enforced by Move wrappers. Substring bytes are copied to an ownedVecbeforenew_byte_vectorto avoid GC relocating source slices.Differential coverage moves from
check_utf8.movetostring.move, keeping utf8 cases and addingindex_of/sub_stringscenarios (including multibyte boundaries viasub_stringasserts).Reviewed by Cursor Bugbot for commit ed7b4ce. Bugbot is set up for automated code reviews on this repo. Configure here.