Skip to content

Commit a6d5fa5

Browse files
committed
v3: preserve array map pointer result origins
1 parent c8286b1 commit a6d5fa5

3 files changed

Lines changed: 128 additions & 5 deletions

File tree

vlib/v3/tests/review_transform_regressions_test.v

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5551,6 +5551,108 @@ fn main() {
55515551
assert out == 'four\nfour'
55525552
}
55535553

5554+
fn test_array_map_keeps_temporary_source_through_dump_result() {
5555+
v3_bin := build_v3_review_transform_ownership()
5556+
source := 'struct Item {
5557+
text string
5558+
}
5559+
5560+
fn make_items() []Item {
5561+
return [Item{
5562+
text: "four"
5563+
}]
5564+
}
5565+
5566+
fn main() {
5567+
values := make_items().map(dump(&it))
5568+
println(values[0].text)
5569+
}
5570+
'
5571+
c_source := gen_c_from_source_with_flags(v3_bin, 'array_map_dump_pointer_result_c',
5572+
'-ownership', source)
5573+
main_body := c_fn_body(c_source, 'int main(int argc, char** argv) {')
5574+
assert !main_body.contains('array__free(&(__map_source_'), main_body
5575+
}
5576+
5577+
fn test_array_map_keeps_temporary_source_through_inherited_struct_update_field() {
5578+
v3_bin := build_v3_review_transform_ownership()
5579+
source := 'struct Item {
5580+
text string
5581+
}
5582+
5583+
struct PointerBox {
5584+
value &Item
5585+
other int
5586+
}
5587+
5588+
fn make_items() []Item {
5589+
return [Item{
5590+
text: "four"
5591+
}]
5592+
}
5593+
5594+
fn main() {
5595+
values := make_items().map(PointerBox{
5596+
...PointerBox{
5597+
value: &it
5598+
}
5599+
other: 1
5600+
}.value)
5601+
println(values[0].text)
5602+
}
5603+
'
5604+
c_source := gen_c_from_source_with_flags(v3_bin, 'array_map_assoc_pointer_result_c',
5605+
'-ownership', source)
5606+
main_body := c_fn_body(c_source, 'int main(int argc, char** argv) {')
5607+
assert !main_body.contains('array__free(&(__map_source_'), main_body
5608+
out := run_good_with_flags(v3_bin, 'array_map_assoc_pointer_result', '-ownership', source)
5609+
assert out == 'four'
5610+
}
5611+
5612+
fn test_array_map_drops_source_for_unselected_helper_result_field() {
5613+
v3_bin := build_v3_review_transform_ownership()
5614+
source := 'struct Item {
5615+
text string
5616+
}
5617+
5618+
struct PointerPair {
5619+
source &Item
5620+
external &Item
5621+
}
5622+
5623+
fn make_items() []Item {
5624+
return [Item{
5625+
text: "source"
5626+
}]
5627+
}
5628+
5629+
fn pair(source &Item, external &Item) PointerPair {
5630+
return unsafe {
5631+
PointerPair{
5632+
source: source
5633+
external: external
5634+
}
5635+
}
5636+
}
5637+
5638+
fn main() {
5639+
external := Item{
5640+
text: "external"
5641+
}
5642+
selected := make_items().map(pair(&it, &external).external)
5643+
println(selected[0].text)
5644+
}
5645+
'
5646+
c_source := gen_c_from_source_with_flags(v3_bin, 'array_map_helper_external_field_c',
5647+
'-ownership', source)
5648+
main_body := c_fn_body(c_source, 'int main(int argc, char** argv) {')
5649+
source_drop_pos := main_body.index('array__free(&(') or { -1 }
5650+
result_move_pos := main_body.index('Array selected = ') or { -1 }
5651+
assert source_drop_pos >= 0 && source_drop_pos < result_move_pos, main_body
5652+
out := run_good_with_flags(v3_bin, 'array_map_helper_external_field', '-ownership', source)
5653+
assert out == 'external'
5654+
}
5655+
55545656
fn test_array_map_drops_source_for_unrelated_pointer_result() {
55555657
v3_bin := build_v3_review_transform_ownership()
55565658
source := 'struct Item {

vlib/v3/transform/array.v

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,7 +2801,7 @@ fn (mut t Transformer) array_map_expr_result_retains_element_address(id flat.Nod
28012801
return t.array_map_lvalue_is_rooted_at_ident(t.a.child(&node, 0), name)
28022802
}
28032803
match node.kind {
2804-
.paren, .cast_expr, .as_expr, .expr_stmt, .field_init {
2804+
.paren, .cast_expr, .as_expr, .dump_expr, .expr_stmt, .field_init {
28052805
return node.children_count > 0
28062806
&& t.array_map_expr_result_retains_element_address(t.a.child(&node, 0), name)
28072807
}
@@ -2827,9 +2827,16 @@ fn (mut t Transformer) array_map_expr_result_retains_element_address(id flat.Nod
28272827
return false
28282828
}
28292829
.selector {
2830-
return node.children_count > 0
2831-
&& t.array_map_selector_result_retains_element_address(t.a.child(&node, 0),
2832-
node.value, name)
2830+
if node.children_count == 0 {
2831+
return false
2832+
}
2833+
for source_arg in t.tc.ownership_call_result_source_args(id) {
2834+
if t.array_map_expr_result_retains_element_address(source_arg, name) {
2835+
return true
2836+
}
2837+
}
2838+
return t.array_map_selector_result_retains_element_address(t.a.child(&node, 0),
2839+
node.value, name)
28332840
}
28342841
.index {
28352842
return t.array_map_index_result_retains_element_address(node, name)
@@ -2897,6 +2904,10 @@ fn (mut t Transformer) array_map_selector_result_retains_element_address(base_id
28972904
elem_name)
28982905
}
28992906
}
2907+
if base.kind == .assoc && base.children_count > 0 {
2908+
return t.array_map_selector_result_retains_element_address(t.a.child(&base, 0),
2909+
field_name, elem_name)
2910+
}
29002911
return false
29012912
}
29022913
return t.array_map_expr_result_retains_element_address(base_id, elem_name)

vlib/v3/types/checker_ownership_d_ownership.v

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10536,7 +10536,8 @@ pub fn (mut tc TypeChecker) ownership_call_result_source_args(id flat.NodeId) []
1053610536
if tc.ownership == unsafe { nil } {
1053710537
return []flat.NodeId{}
1053810538
}
10539-
call_id := tc.ownership_unwrap_expr(id)
10539+
projection := tc.ownership_call_projection(id) or { return []flat.NodeId{} }
10540+
call_id := projection.call_id
1054010541
if !tc.valid_node_id(call_id) {
1054110542
return []flat.NodeId{}
1054210543
}
@@ -10553,11 +10554,20 @@ pub fn (mut tc TypeChecker) ownership_call_result_source_args(id flat.NodeId) []
1055310554
}
1055410555
}
1055510556
for slot in tc.ownership_state().ownership_fn_return_params[call_name] {
10557+
if projection.suffix.len > 0 && slot.slot_idx != 0 {
10558+
continue
10559+
}
1055610560
if slot.param_idx !in param_indices {
1055710561
param_indices << slot.param_idx
1055810562
}
1055910563
}
1056010564
for desc in tc.ownership_state().ownership_fn_return_param_descs[call_name] {
10565+
if projection.suffix.len > 0
10566+
&& (desc.slot_idx != 0
10567+
|| (desc.target_suffix.len > 0
10568+
&& !ownership_storage_keys_overlap(desc.target_suffix, projection.suffix))) {
10569+
continue
10570+
}
1056110571
if desc.param_idx !in param_indices {
1056210572
param_indices << desc.param_idx
1056310573
}

0 commit comments

Comments
 (0)