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
#![cfg(not(any(
feature = "parser_tests",
feature = "analyzer_tests",
feature = "codegen_tests",
feature = "interpreter_tests",
feature = "conformance_tests",
feature = "integration_tests",
)))]
#[path = "common/test_utils.rs"]
mod test_utils;
/// TDD test: Mutable method calls in let bindings should trigger &mut inference
///
/// Bug: `let x = loader.load(...)` where `load()` requires `&mut self`
/// doesn't trigger &mut inference for `loader` parameter because `is_mutated`
/// only checks `Statement::Expression`, not `Statement::Let` values.
///
/// Root Cause: `is_mutated` doesn't check the value expression of let bindings
/// for mutable method calls.
///
/// Fix: Add `Statement::Let` case in `is_mutated` to check value for
/// mutable method calls.
#[test]
fn test_let_binding_with_mut_method_call() {
let source = r#"
pub struct Loader {
count: i32,
items: Vec<string>,
}
impl Loader {
pub fn new() -> Loader {
Loader { count: 0, items: Vec::new() }
}
pub fn load(self, name: string, size: i32) -> string {
self.count = self.count + 1
self.items.push(name)
name
}
}
pub fn load_stuff(loader: Loader) -> Vec<string> {
let mut results: Vec<string> = Vec::new()
let a = loader.load("first".to_string(), 100)
let b = loader.load("second".to_string(), 200)
results.push(a)
results.push(b)
results
}
"#;
let generated = test_utils::compile_single(source);
println!("Generated:\n{}", generated);
// THE WINDJAMMER WAY: Automatic ownership inference!
// User writes `loader: Loader` (no & or &mut)
// Compiler infers `loader: &mut Loader` because loader.load() mutates (self.count++)
// This is automatic ownership inference - compiler does the hard work!
assert!(
generated.contains("loader: &mut Loader"),
"Parameter should be inferred as `&mut Loader` (automatic ownership). Got:\n{}",
generated
);
}