rusty_cpp/analysis/
this_tracking.rs

1use std::collections::{HashMap, HashSet};
2use crate::ir::BorrowKind;
3use crate::parser::MethodQualifier;
4
5/// Tracks the state of member fields within a method based on 'this' pointer semantics
6///
7/// Enforces Rust-like rules:
8/// - Const methods (&self): Can read fields, cannot modify or move
9/// - Non-const methods (&mut self): Can read and modify fields, CANNOT move fields
10/// - Rvalue methods (self): Can do anything including moving fields
11#[derive(Debug, Clone)]
12pub struct ThisPointerTracker {
13    /// The qualifier of the current method (const, non-const, or &&)
14    method_qualifier: Option<MethodQualifier>,
15
16    /// Fields that have been moved (no longer accessible)
17    moved_fields: HashSet<String>,
18
19    /// Fields that are currently borrowed and their borrow kind
20    borrowed_fields: HashMap<String, BorrowKind>,
21}
22
23impl ThisPointerTracker {
24    /// Create a new tracker for a method with the given qualifier
25    pub fn new(method_qualifier: Option<MethodQualifier>) -> Self {
26        Self {
27            method_qualifier,
28            moved_fields: HashSet::new(),
29            borrowed_fields: HashMap::new(),
30        }
31    }
32
33    /// Check if we can read a member field
34    ///
35    /// Rules:
36    /// - All method types can read fields (const, non-const, &&)
37    /// - Cannot read moved fields
38    pub fn can_read_member(&self, field: &str) -> Result<(), String> {
39        if self.moved_fields.contains(field) {
40            return Err(format!("Cannot read field '{}': field has been moved", field));
41        }
42        Ok(())
43    }
44
45    /// Check if we can modify a member field
46    ///
47    /// Rules:
48    /// - Const methods (&self): CANNOT modify
49    /// - Non-const methods (&mut self): CAN modify
50    /// - Rvalue methods (self): CAN modify
51    /// - Cannot modify moved fields
52    /// - Cannot modify immutably borrowed fields
53    pub fn can_modify_member(&self, field: &str) -> Result<(), String> {
54        if self.moved_fields.contains(field) {
55            return Err(format!("Cannot modify field '{}': field has been moved", field));
56        }
57
58        // Check method qualifier
59        if let Some(MethodQualifier::Const) = self.method_qualifier {
60            return Err(format!(
61                "Cannot modify field '{}' in const method (use non-const method for &mut self semantics)",
62                field
63            ));
64        }
65
66        // Check if field is borrowed immutably
67        if let Some(BorrowKind::Immutable) = self.borrowed_fields.get(field) {
68            return Err(format!(
69                "Cannot modify field '{}': field is currently borrowed immutably",
70                field
71            ));
72        }
73
74        Ok(())
75    }
76
77    /// Check if we can move a member field
78    ///
79    /// Rules:
80    /// - Const methods (&self): CANNOT move
81    /// - Non-const methods (&mut self): CANNOT move (key Rust restriction!)
82    /// - Rvalue methods (self): CAN move
83    /// - Cannot move already-moved fields
84    /// - Cannot move borrowed fields
85    pub fn can_move_member(&self, field: &str) -> Result<(), String> {
86        if self.moved_fields.contains(field) {
87            return Err(format!("Cannot move field '{}': field has already been moved", field));
88        }
89
90        // Check if field is borrowed
91        if self.borrowed_fields.contains_key(field) {
92            return Err(format!(
93                "Cannot move field '{}': field is currently borrowed",
94                field
95            ));
96        }
97
98        // Check method qualifier - this is the key restriction
99        match self.method_qualifier {
100            Some(MethodQualifier::Const) => {
101                Err(format!(
102                    "Cannot move field '{}' from const method (requires && method for self ownership)",
103                    field
104                ))
105            }
106            Some(MethodQualifier::NonConst) => {
107                Err(format!(
108                    "Cannot move field '{}' from &mut self method (use && qualified method for self ownership)",
109                    field
110                ))
111            }
112            Some(MethodQualifier::RvalueRef) => {
113                // && methods have full ownership - can move
114                Ok(())
115            }
116            None => {
117                // Not in a method context - allow for now (free functions)
118                Ok(())
119            }
120        }
121    }
122
123    /// Check if we can borrow a member field
124    ///
125    /// Rules:
126    /// - Const methods: Can only create immutable borrows
127    /// - Non-const methods: Can create mutable or immutable borrows
128    /// - Rvalue methods: Can create any borrow
129    /// - Cannot borrow moved fields
130    /// - Respect existing borrows (no mutable + immutable, no multiple mutable)
131    pub fn can_borrow_member(&self, field: &str, kind: BorrowKind) -> Result<(), String> {
132        if self.moved_fields.contains(field) {
133            return Err(format!("Cannot borrow field '{}': field has been moved", field));
134        }
135
136        // Const methods can only create immutable borrows
137        if let Some(MethodQualifier::Const) = self.method_qualifier {
138            if matches!(kind, BorrowKind::Mutable) {
139                return Err(format!(
140                    "Cannot create mutable borrow of field '{}' in const method",
141                    field
142                ));
143            }
144        }
145
146        // Check for conflicting borrows
147        if let Some(existing_kind) = self.borrowed_fields.get(field) {
148            match (existing_kind, kind) {
149                (BorrowKind::Mutable, _) => {
150                    return Err(format!(
151                        "Cannot borrow field '{}': already borrowed mutably",
152                        field
153                    ));
154                }
155                (BorrowKind::Immutable, BorrowKind::Mutable) => {
156                    return Err(format!(
157                        "Cannot borrow field '{}' mutably: already borrowed immutably",
158                        field
159                    ));
160                }
161                (BorrowKind::Immutable, BorrowKind::Immutable) => {
162                    // Multiple immutable borrows are OK
163                    Ok(())
164                }
165            }
166        } else {
167            Ok(())
168        }
169    }
170
171    /// Mark a field as moved
172    pub fn mark_field_moved(&mut self, field: String) {
173        self.moved_fields.insert(field.clone());
174        self.borrowed_fields.remove(&field); // Can't be borrowed if moved
175    }
176
177    /// Mark a field as borrowed
178    pub fn mark_field_borrowed(&mut self, field: String, kind: BorrowKind) {
179        self.borrowed_fields.insert(field, kind);
180    }
181
182    /// Clear a borrow on a field (when reference goes out of scope)
183    pub fn clear_field_borrow(&mut self, field: &str) {
184        self.borrowed_fields.remove(field);
185    }
186
187    /// Get the method qualifier
188    pub fn method_qualifier(&self) -> Option<&MethodQualifier> {
189        self.method_qualifier.as_ref()
190    }
191
192    /// Check if a field has been moved
193    pub fn is_field_moved(&self, field: &str) -> bool {
194        self.moved_fields.contains(field)
195    }
196
197    /// Check if a field is currently borrowed
198    pub fn is_field_borrowed(&self, field: &str) -> bool {
199        self.borrowed_fields.contains_key(field)
200    }
201}