Add support for accessing single-element aggregates in #traverseProjection - #657
Conversation
…ction - 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.
| // Closure function that takes &MyStruct reference | ||
| let get_value = |struct_ref: &MyStruct| { | ||
| struct_ref.data | ||
| }; |
There was a problem hiding this comment.
(probably off-topic)
While reading this code, I was thinking, what if we were using the struct_list in scope (capturing the variable in the closure), like this:
let get_value = | i: usize | { struct_list[i].data }We should investigate closures a bit more (but unrelated to p-token)
| </k> | ||
| ``` | ||
|
|
||
| If an Aggregate contains only one element and #traverseProjection becomes stuck, you can directly access this element. For more details, you may remove this rule and run `tests/integration/data/prove-rs/closure_access_struct.rs`. |
There was a problem hiding this comment.
Maybe add text describing what we would see in that test when removing the rule.
Anyone who reads it will understand better without having to repeat your experiments.
There was a problem hiding this comment.
Updated the description!
| │ | ||
| │ (277 steps) | ||
| └─ 3 (stuck, leaf) | ||
| #traverseProjection ( toLocal ( 19 ) , thunk ( #decodeConstant ( constantKindAll |
There was a problem hiding this comment.
Could we write the test program in a way that avoids this constant allocation?
Maybe using a literal array of i32 and producing the struct_list via into_iter, map, and collect?
Would be nicer to have a test that terminates with the fix.
There was a problem hiding this comment.
Is that something like:
struct MyStruct {
data: i32
}
fn main() {
// Create data dynamically using iterator pattern to avoid constant allocation
let data = vec![10, 20, 30, 40, 50];
let struct_list: Vec<MyStruct> = data.into_iter()
.map(|d| MyStruct { data: d })
.collect();
// Closure function that takes &MyStruct reference
let get_value = |struct_ref: &MyStruct| {
struct_ref.data
};
// Use closure to access struct field
let result = get_value(&struct_list[2]);
// Verify result
assert!(result == 30);
}There was a problem hiding this comment.
- Initial Attempt: The new test avoided constant allocation but failed with TypeError: 'NoneType' object is not subscriptable in KMIR's smir.py:183.
- First Bug Fix: Found that some functions have body: None (specifically alloc::alloc::__rust_no_alloc_shim_is_unstable). Fixed by adding null check in call_edges property.
- Second Bug Fix: Encountered KeyError: 131 in reduce_to method. Fixed by filtering out non-existent types from the reachable set.
- Root Cause Discovery: Investigated what "type 131" actually is. Found that 131 is not a function type but a span ID (source location identifier) that appears in a StorageLive statement:
{'kind': {'StorageLive': 15}, 'span': 131}.
There was a problem hiding this comment.
It encounters a more weird issue than before.
There was a problem hiding this comment.
OK nevermind, then we keep this test for now .
The type 131 still exists, IDs of types and spans are disjoint so a span 131 does not mean there is no type 131. (BTW type and function IDs aren't disjoint).
There was a problem hiding this comment.
Thank you. I'm still learning. So it is a bug in smir-json?
There was a problem hiding this comment.
Not a bug, just that we don't extract all types. (take a look at the TyVisitor https://github.com/runtimeverification/stable-mir-json/blob/master/src/printer.rs#L520)
There was a problem hiding this comment.
Thank you. Let me learn about this.
…rseProjection - Expanded the explanation of accessing single-element aggregates when #traverseProjection becomes stuck. - Clarified the behavior of the new rule and its impact on execution steps. - Emphasized the importance of the rule for closures accessing struct fields.
| │ | ||
| │ (277 steps) | ||
| └─ 3 (stuck, leaf) | ||
| #traverseProjection ( toLocal ( 19 ) , thunk ( #decodeConstant ( constantKindAll |
There was a problem hiding this comment.
OK nevermind, then we keep this test for now .
The type 131 still exists, IDs of types and spans are disjoint so a span 131 does not mean there is no type 131. (BTW type and function IDs aren't disjoint).
…ction (#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.
…ction (#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.
Uh oh!
There was an error while loading. Please reload this page.