Skip to content

Commit 26303ce

Browse files
committed
Add support for accessing single-element aggregates in #traverseProjection (#657)
- Updated documentation to explain how to directly access elements of an Aggregate when #traverseProjection becomes stuck. - Introduced a new rule for handling single-element aggregates in the semantics. - Added a new test case for closure access to a struct, ensuring correct behavior. - Updated integration tests to include the new failure case for closure access to structs.
1 parent 50aefe8 commit 26303ce

File tree

5 files changed

+68
-1
lines changed

5 files changed

+68
-1
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ __pycache__/
44
/deps/.stable-mir-json
55
/.vscode/
66
kmir/src/tests/integration/data/**/target
7-
.DS_Store
7+
.DS_Store
8+
proof/

kmir/src/kmir/kdist/mir-semantics/rt/data.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,30 @@ This is done without consideration of the validity of the Downcast[^downcast].
418418
</k>
419419
```
420420

421+
If an Aggregate contains only one element and #traverseProjection becomes stuck, you can directly access this element.
422+
423+
Without this rule, the test `closure_access_struct-fail.rs` demonstrates the following behavior:
424+
- The execution gets stuck after 192 steps at `#traverseProjection ( toLocal ( 2 ) , Aggregate ( variantIdx ( 0 ) , ListItem ( ... ) ) , ... )`
425+
- The stuck state occurs because there's a Deref projection that needs to be applied to the single element of this Aggregate, but the existing Deref rules only handle pointers and references, not Aggregates
426+
427+
With this rule enabled:
428+
- The execution progresses further to 277 steps before getting stuck
429+
- It gets stuck at a different location: `#traverseProjection ( toLocal ( 19 ) , thunk ( #decodeConstant ( constantKindAll ... ) ) , ... )`
430+
- The rule automatically unwraps the single-element Aggregate, allowing the field access to proceed
431+
432+
This rule is essential for handling closures that access struct fields, as MIR represents certain struct accesses through single-element Aggregates that need to be unwrapped.
433+
434+
```k
435+
rule <k> #traverseProjection(
436+
DEST,
437+
Aggregate(_, ARGS),
438+
PROJS,
439+
CTXTS
440+
)
441+
=> #traverseProjection(DEST, getValue(ARGS, 0), PROJS, CTXTS) ... </k>
442+
requires size(ARGS) ==Int 1 [preserves-definedness, priority(100)]
443+
```
444+
421445
#### Ranges
422446

423447
An `Index` projection operates on an array or slice (`Range`) value, to access an element of the array.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
struct MyStruct {
2+
data: i32
3+
}
4+
5+
fn main() {
6+
// List of MyStruct instances
7+
let struct_list = [
8+
MyStruct { data: 10 },
9+
MyStruct { data: 20 },
10+
MyStruct { data: 30 },
11+
MyStruct { data: 40 },
12+
MyStruct { data: 50 }
13+
];
14+
15+
// Closure function that takes &MyStruct reference
16+
let get_value = |struct_ref: &MyStruct| {
17+
struct_ref.data
18+
};
19+
20+
// Use list call style, passing reference
21+
let result = get_value(&struct_list[2]);
22+
23+
// Verify result
24+
assert_eq!(result, 30);
25+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
┌─ 1 (root, init)
3+
│ #execTerminator ( terminator ( ... kind: terminatorKindCall ( ... func: operandC
4+
│ span: 0
5+
6+
│ (277 steps)
7+
└─ 3 (stuck, leaf)
8+
#traverseProjection ( toLocal ( 19 ) , thunk ( #decodeConstant ( constantKindAll
9+
function: main
10+
span: 106
11+
12+
13+
┌─ 2 (root, leaf, target, terminal)
14+
│ #EndProgram ~> .K
15+
16+

kmir/src/tests/integration/test_integration.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
'checked_arithmetic-fail',
5353
'offset-u8-fail',
5454
'pointer-cast-length-test-fail',
55+
'closure_access_struct-fail',
5556
]
5657

5758

0 commit comments

Comments
 (0)