Handle struct field write through array index in emit#72
Handle struct field write through array index in emit#72angelica-moreira wants to merge 3 commits into
Conversation
| struct_name.val.clone(), | ||
| field.val.clone(), | ||
| )); | ||
| return arr_doc |
There was a problem hiding this comment.
The early return skips the annotated wrapper, we should probably split this function in two (or make annotated take a closure).
Yeah, it would be a lot cleaner if we could use Right now the code duplicates both the arr and idx expressions, which it shouldn't (if they have side effects). We should probably generate a call to an auxiliary function like Please also add a test case. |
07bfb1d to
1a885a6
Compare
Handle arr[i].field = val by emitting:
let __arr = arr;
let __idx = idx;
let __cur = __arr.(__idx);
let __val = rhs;
__arr.(__idx) <- { __cur with field = __val };
This uses Pulse-native let-statement bindings to:
- Avoid duplicating arr/idx expressions (side-effect safety).
- Read the current element into a pure variable before the
record update, which Pulse's type checker requires.
Addresses review feedback:
- Extract emit_assign() helper so the Assign arm no longer
bypasses the annotated() wrapper in emit_stmt.
- Use let-bindings for arr, idx, current element, and rhs
to avoid duplicating expressions that may have side effects.
- Add test/struct_array_write.c exercising the pattern.
Verified: the generated Pulse code (with SizeT index) passes
F* verification with all conditions discharged successfully.
Scope limitation: Only handles one level of arr[i].field.
Deeper patterns like arr[i].field.subfield or ptr->arr[i].field
would need further work.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1a885a6 to
cf75491
Compare
Generic helper for struct field writes through array index.
Emits update_arr_with arr idx (fun cur -> { cur with field = val }).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
I believe I am done. I added
Now we do not have more duplicated I also made spec expressions ( I added a test case like you requested, you can find it here test/struct_array_write.c with three functions (set_x, set_y, set_both), all with pre and postconditions. |
…se only syntax. I also added ensures cababilities
cff1524 to
4f4f9f5
Compare
Can you please turn this into: I'd really like to avoid generating extra let-bindings here (which might break when we start supporting things like
There is no need to do that distinction, and I'd really like to avoid it (to avoid potential divergence in behavior). I tried removing the is_spec handling, and what breaks is that we were missing parentheses around the Pulse term for ExprT::Index. Please just add the parentheses instead.
The test case is great, thanks. |
Problem
arr[idx].field = valproducesadmit()in the F*/Pulse output.In
StmtT::Assign, the LHSMember(Index(arr, idx), field)fallsthrough to
emit_lvalue. SinceExprT::IndexreturnsExprKind::RValue(correct — Pulse's
arr.(idx)reads without!),emit_lvaluegets anRValue and emits
TODO/admit().Fix
Extract
emit_assign()helper fromemit_stmt()so the Assign arm stays inside theannotated()wrapper. Pattern-matchMember(Index(arr, idx), field)in the new helper, emitting a call toupdate_arr_with:pts[i].x = val;becomes:
let __val = (!var_val); update_arr_with (!var_pts) (!var_i) (fun __cur -> { __cur with struct_point__x = __val });update_arr_withis a new generic helper added toPulse.Lib.C.Array.fstithat reads, applies a pure function, and writes back. Its postcondition guarantees the element at the index equals f applied to the old element, which lets F* discharge _ensures specs likepts[i].x == val.Spec expressions (
_requires,_ensures,_invariant) now emit pure F* syntax for array indexing ,Seq.index (value_of arr) (SizeT.v idx)instead of the Pulse-only syntax I previous usedarr.(idx).arr[i].field. Deeper patterns likearr[i].field.subfieldorptr->arr[i].fieldwould need further work.