1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#![cfg(any(
not(any(
feature = "parser_tests",
feature = "analyzer_tests",
feature = "codegen_tests",
feature = "interpreter_tests",
feature = "conformance_tests",
feature = "integration_tests",
)),
feature = "analyzer_tests",
))]
/// TDD Test: Vec index auto-clone must be suppressed in certain contexts
///
/// Bug: The compiler adds .clone() to Vec<T>[i] for non-Copy types, but
/// this is incorrect in three contexts:
///
/// 1. Assignment target: `self.vec[i] = value` → must NOT clone (can't assign to .clone())
/// 2. Borrow context: `&self.vec[i]` → must NOT clone (want reference to original)
/// 3. Mutable borrow context: `&mut self.vec[i]` → must NOT clone (can't take &mut of temp)
///
/// Root cause: The Expression::Index handler's auto-clone fallback doesn't check
/// whether we're generating an assignment target or inside a reference expression.
///
/// Discovered via dogfooding: ecs/components.wj (ComponentArray<T>)
#[path = "common/test_utils.rs"]
mod test_utils;
#[test]
fn test_vec_index_no_clone_on_assignment_target() {
// Bug: `self.items[i] = value` generates `self.items[i as usize].clone() = value`
// The .clone() on the LEFT side of assignment is always wrong.
let source = r#"
struct Item {
name: string,
count: i32,
}
struct Container {
items: Vec<Item>,
}
impl Container {
pub fn new() -> Container {
Container { items: vec![] }
}
pub fn update_at(self, index: i32, item: Item) {
self.items[index as usize] = item
}
}
fn main() {
let mut c = Container::new()
c.items.push(Item { name: "old".to_string(), count: 0 })
c.update_at(0, Item { name: "new".to_string(), count: 1 })
println("done")
}
"#;
let (rust_code, compiles) = test_utils::compile_single_check(source);
// The assignment target must NOT have .clone()
// Bad: self.items[index as usize].clone() = item
// Good: self.items[index as usize] = item
assert!(
!rust_code.contains(".clone() = "),
"Assignment target must NOT have .clone()!\nGenerated:\n{}",
rust_code
);
assert!(
compiles,
"Generated Rust must compile!\nGenerated:\n{}",
rust_code
);
}
#[test]
fn test_vec_index_no_clone_on_borrow() {
// Bug: `&self.items[i]` generates `&self.items[i as usize].clone()`
// Taking a reference to a clone is pointless and wrong (reference to temporary).
let source = r#"
struct Item {
name: string,
count: i32,
}
struct Container {
items: Vec<Item>,
}
impl Container {
pub fn new() -> Container {
Container { items: vec![] }
}
pub fn get_ref(self, index: i32) -> &Item {
self.items[index as usize]
}
}
fn main() {
let c = Container::new()
println("done")
}
"#;
let rust_code = test_utils::compile_single(source);
// Borrow context must NOT have .clone()
// Bad: &self.items[index as usize].clone()
// Good: &self.items[index as usize]
assert!(
!rust_code.contains(".clone()"),
"Borrow of Vec index must NOT have .clone()!\nGenerated:\n{}",
rust_code
);
}
#[test]
fn test_vec_index_no_clone_on_mut_borrow() {
// Bug: `&mut self.items[i]` generates `&mut self.items[i as usize].clone()`
// Can't take &mut of a temporary.
let source = r#"
struct Item {
name: string,
count: i32,
}
struct Container {
items: Vec<Item>,
}
impl Container {
pub fn new() -> Container {
Container { items: vec![] }
}
pub fn get_mut_ref(self, index: i32) -> &mut Item {
self.items[index as usize]
}
}
fn main() {
let mut c = Container::new()
println("done")
}
"#;
let rust_code = test_utils::compile_single(source);
// Mutable borrow context must NOT have .clone()
// Bad: &mut self.items[index as usize].clone()
// Good: &mut self.items[index as usize]
assert!(
!rust_code.contains(".clone()"),
"Mutable borrow of Vec index must NOT have .clone()!\nGenerated:\n{}",
rust_code
);
}