|
| 1 | +/* |
| 2 | + * struct_deep_copy.ez - copy() on structs and struct-containing shapes |
| 3 | + * performs a deep copy of collection-typed fields. |
| 4 | + * |
| 5 | + * Regression for #1466 (commits 9b055bd + a366112): |
| 6 | + * - 9b055bd: TK_STRUCT branch in copy() deep-copies direct array/map |
| 7 | + * fields instead of falling through to a bitwise C struct copy. |
| 8 | + * - a366112: unified recursive deep-copy emitter covers transitive |
| 9 | + * struct nesting, arrays of structs with collection fields, and |
| 10 | + * maps whose values are structs with collection content. |
| 11 | + * |
| 12 | + * Three user-observable independence probes. A fourth gap — map[K:Struct] |
| 13 | + * where Struct holds a collection — is correct internally (verified by |
| 14 | + * reading the generated C during QA) but not observable from EZ user |
| 15 | + * code today because map reads return struct copies, so mutations can't |
| 16 | + * propagate back to the backing storage for an independence check |
| 17 | + * without additional ref semantics. |
| 18 | + */ |
| 19 | + |
| 20 | +const Bag struct { |
| 21 | + name string |
| 22 | + items [int] |
| 23 | +} |
| 24 | + |
| 25 | +const Inner struct { |
| 26 | + tag string |
| 27 | + nums [int] |
| 28 | +} |
| 29 | + |
| 30 | +const Outer struct { |
| 31 | + id int |
| 32 | + inner Inner |
| 33 | +} |
| 34 | + |
| 35 | +do main() { |
| 36 | + println("=== Struct Deep Copy Test ===") |
| 37 | + mut passed int = 0 |
| 38 | + mut failed int = 0 |
| 39 | + |
| 40 | + // -- direct array field (fix in 9b055bd) -- |
| 41 | + mut bag Bag = Bag{name: "orig", items: {1, 2, 3}} |
| 42 | + mut bag_copy Bag = copy(bag) |
| 43 | + bag_copy.items[0] = 999 |
| 44 | + bag_copy.name = "copy" |
| 45 | + if bag.name == "orig" && bag.items[0] == 1 && |
| 46 | + bag_copy.name == "copy" && bag_copy.items[0] == 999 { |
| 47 | + println(" [PASS] direct array field in struct") |
| 48 | + passed += 1 |
| 49 | + } otherwise { |
| 50 | + println(" [FAIL] direct array field in struct") |
| 51 | + failed += 1 |
| 52 | + } |
| 53 | + |
| 54 | + // -- transitive struct-in-struct with inner collection (fix in a366112) -- |
| 55 | + mut o1 Outer = Outer{id: 1, inner: Inner{tag: "x", nums: {10, 20, 30}}} |
| 56 | + mut o2 Outer = copy(o1) |
| 57 | + o2.inner.nums[0] = 888 |
| 58 | + o2.inner.tag = "y" |
| 59 | + if o1.inner.nums[0] == 10 && o1.inner.tag == "x" && |
| 60 | + o2.inner.nums[0] == 888 && o2.inner.tag == "y" { |
| 61 | + println(" [PASS] transitive struct-in-struct-with-array") |
| 62 | + passed += 1 |
| 63 | + } otherwise { |
| 64 | + println(" [FAIL] transitive struct-in-struct-with-array") |
| 65 | + failed += 1 |
| 66 | + } |
| 67 | + |
| 68 | + // -- array of structs with a collection field (fix in a366112) -- |
| 69 | + mut bags [Bag] = {Bag{name: "a", items: {1, 2}}, Bag{name: "b", items: {3, 4}}} |
| 70 | + mut bags_copy [Bag] = copy(bags) |
| 71 | + bags_copy[0].items[0] = 777 |
| 72 | + bags_copy[0].name = "A" |
| 73 | + if bags[0].items[0] == 1 && bags[0].name == "a" && |
| 74 | + bags_copy[0].items[0] == 777 && bags_copy[0].name == "A" { |
| 75 | + println(" [PASS] array of structs with collection field") |
| 76 | + passed += 1 |
| 77 | + } otherwise { |
| 78 | + println(" [FAIL] array of structs with collection field") |
| 79 | + failed += 1 |
| 80 | + } |
| 81 | + |
| 82 | + println("") |
| 83 | + println("Results: ${passed} passed, ${failed} failed") |
| 84 | + |
| 85 | + if failed > 0 { |
| 86 | + println("SOME TESTS FAILED") |
| 87 | + } otherwise { |
| 88 | + println("ALL TESTS PASSED") |
| 89 | + } |
| 90 | +} |
0 commit comments