Add slice construction from array literals#158
Conversation
d1cab50 to
eb0c396
Compare
eb0c396 to
adb2eab
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: adb2eab745
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let base_idx = builder.push_existential(chc::Sort::array( | ||
| chc::Sort::int(), | ||
| elem_ty.to_sort(), | ||
| )); | ||
| let mut arr_term: chc::Term<PlaceTypeVar> = chc::Term::var(base_idx.into()); |
There was a problem hiding this comment.
Start array literals from a canonical empty array
When two array literals with the same visible elements are compared, this existential base makes their Seq array components arbitrary outside 0..N. Since the [T; N] model is model::Seq and equality/PartialEq compares the underlying tuple/array extensionally, a case like comparing two independently constructed [1i32, 2] values cannot be proved equal even though Rust array equality only depends on the initialized elements. Build the literal from a canonical array_empty term instead of a fresh unconstrained array so equal literals don't differ outside their length.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds verifier support for constructing &[T]/&mut [T] slices from array literals ([T; N]) while preserving refinement-type tracking through indexing, and fixes a MIR slice-indexing reconstruction edge case involving PtrMetadata.
Changes:
- Teach the MIR analyzer to model array literals as
Seq<T>by folding elementstores and recording a static length; add handling for type-level consts andCopyForDeref. - Treat
&[T; N] → &[T]unsize coercions as model-preserving, and fixremove_bounds_check_setupto avoid NOP’ing the slice receiver local in a specificPtrMetadatashape. - Add 6 UI tests covering correct slice reads/writes through array-literal-backed slices and expected failures (unsat/out-of-bounds/stale read).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/analyze/basic_block.rs | Models array literal construction as a Seq<T> and extends rvalue/const handling to support the new slice-from-array behavior. |
| src/analyze/reconstruct_slice_indexing.rs | Fixes bounds-check temporary cleanup to avoid erasing the slice receiver assignment in certain MIR patterns. |
| std.rs | Adds a [T; N] Model impl mapping arrays to the same Seq<T> model as slices. |
| tests/ui/pass/array_literal_1.rs | Pass case: read s[0] after coercing &[T; N] to &[T]. |
| tests/ui/pass/array_literal_2.rs | Pass case: access last element via slice indexing. |
| tests/ui/pass/array_literal_3.rs | Pass case: write through &mut [T] and observe updated value. |
| tests/ui/fail/array_literal_1.rs | Fail case: wrong expected value yields Unsat. |
| tests/ui/fail/array_literal_2.rs | Fail case: out-of-bounds slice index yields Unsat. |
| tests/ui/fail/array_literal_3.rs | Fail case: reading stale value after write yields Unsat. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Handle `Rvalue::Aggregate(Array, ...)` by building a Seq<T> model (Box<Array<Int,T>>, Box<Int>) whose array component is the store-fold of all literal elements and whose length is the static count N. Also handle `mir::Const::Ty` (type-level constants, e.g. array length N) by extracting the scalar integer and delegating to `const_value_ty`. Map `[T; N]` to `model::Seq<T::Ty>` in `std.rs`, matching `[T]` and `Vec<T>`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013oVufAKCMzsLRnQ8F58PdP
Support the MIR operations needed to turn `[T; N]` into `&[T]` and index it: - `Rvalue::CopyForDeref`: pass-through to the place type (coerce-for-deref). - `Rvalue::Cast(PointerCoercion::Unsize)`: identity coercion since `[T; N]` and `[T]` share the same `Seq<T>` model. Fix a bug in `remove_bounds_check_setup` where the slice receiver local was incorrectly NOP'd when `PtrMetadata` was applied directly to it. The receiver must remain live for the reconstructed `Index::index` call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013oVufAKCMzsLRnQ8F58PdP
ab15156 to
878aa3c
Compare
Adds support for constructing
&[T]slices from array literals ([T; N]) and indexing through them with full refinement-type tracking.Changes
src/analyze/basic_block.rsAggregateKind::Array: Build theSeq<T>model from array literal elements by foldingstorecalls to pin each element at its index and recording the static length. This is intentionally model-aware — following the precedent of Verus, Prusti, and Creusot, array literal construction is a primitive whose semantics the verifier encodes directly (analogous to integer arithmetic), rather than routing through user-visible extern specs.Rvalue::CopyForDeref: Delegate toenv.place_type(same asUse).Rvalue::Cast(PointerCoercion::Unsize): Identity pass-through for&[T; N] → &[T](both share the sameSeq<T>model).mir::Const::Ty: Handle type-level constants (const generics, e.g. array lengthN) by extracting their scalar value.src/analyze/reconstruct_slice_indexing.rsremove_bounds_check_setupwas incorrectly NOP'ing the slice receiver local whenPtrMetadatawas applied directly to it (rather than to a raw-pointer temporary). This caused the receiver's assignment to be erased in-block, making it appear live-in to the entry block, and ultimately panicking inInstantiator::instantiatewhen a synthetic unit parameter carried aRefinedTypeVar::Valuerefinement withvalue_var = None. Fix: skipraw_place.localwhen it equals the receiver local.std.rs[T; N]model:impl<T: Model, const N: usize> Model for [T; N]mapping tomodel::Seq<T::Ty>, consistent with[T].Tests
6 new UI tests (3 pass / 3 fail):
pass/array_literal_1.rs[1i32, 2, 3], coerce to&[i32], asserts[0] == 1pass/array_literal_2.rspass/array_literal_3.rs&mut [i32], write through slice, verify updated valuefail/array_literal_1.rsfail/array_literal_2.rsfail/array_literal_3.rs