rusty_cpp/ir/
mod.rs

1use crate::parser::{CppAst, MethodQualifier};
2use petgraph::graph::{DiGraph, NodeIndex};
3use std::collections::HashMap;
4use crate::debug_println;
5
6/// Parse operator name from a function name
7/// Returns the operator symbol (e.g., "*", "=", "==") or None
8fn parse_operator_name(func_name: &str) -> Option<&str> {
9    // Find the last occurrence of "operator" keyword
10    if let Some(pos) = func_name.rfind("operator") {
11        let op = &func_name[pos + "operator".len()..];
12        if !op.is_empty() {
13            return Some(op);
14        }
15    }
16    None
17}
18
19/// Check if function is operator* (dereference), not operator*= or operator*
20fn is_dereference_operator(func_name: &str) -> bool {
21    if let Some(op) = parse_operator_name(func_name) {
22        op == "*"
23    } else {
24        false
25    }
26}
27
28/// Check if function is operator= (assignment), not operator==, !=, <=, >=
29fn is_assignment_operator(func_name: &str) -> bool {
30    if let Some(op) = parse_operator_name(func_name) {
31        op == "="
32    } else {
33        false
34    }
35}
36
37/// Check if function is operator-> (member access)
38fn is_member_access_operator(func_name: &str) -> bool {
39    if let Some(op) = parse_operator_name(func_name) {
40        op == "->"
41    } else {
42        false
43    }
44}
45
46/// Extract the full object path and final field from a nested MemberAccess expression
47/// For `o.inner.data`, returns Some(("o.inner", "data"))
48/// For `o.field`, returns Some(("o", "field"))
49/// For other expressions, returns None
50fn extract_member_path(expr: &crate::parser::Expression) -> Option<(String, String)> {
51    match expr {
52        crate::parser::Expression::MemberAccess { object, field } => {
53            match object.as_ref() {
54                crate::parser::Expression::Variable(var_name) => {
55                    // Simple case: var.field
56                    Some((var_name.clone(), field.clone()))
57                }
58                crate::parser::Expression::MemberAccess { .. } => {
59                    // Nested case: obj.path.field - recursively build the path
60                    let object_path = extract_full_member_path(object.as_ref())?;
61                    Some((object_path, field.clone()))
62                }
63                _ => None
64            }
65        }
66        _ => None
67    }
68}
69
70/// Extract the full path string from a MemberAccess chain
71/// For `o.inner.data`, returns "o.inner.data"
72/// For Variable("x"), returns "x"
73fn extract_full_member_path(expr: &crate::parser::Expression) -> Option<String> {
74    match expr {
75        crate::parser::Expression::Variable(name) => Some(name.clone()),
76        crate::parser::Expression::MemberAccess { object, field } => {
77            let obj_path = extract_full_member_path(object.as_ref())?;
78            Some(format!("{}.{}", obj_path, field))
79        }
80        _ => None
81    }
82}
83
84#[derive(Debug, Clone)]
85pub struct IrProgram {
86    pub functions: Vec<IrFunction>,
87    #[allow(dead_code)]
88    pub ownership_graph: OwnershipGraph,
89    /// RAII Phase 2: Types with user-defined destructors
90    pub user_defined_raii_types: std::collections::HashSet<String>,
91}
92
93#[derive(Debug, Clone)]
94pub struct IrFunction {
95    #[allow(dead_code)]
96    pub name: String,
97    pub cfg: ControlFlowGraph,
98    pub variables: HashMap<String, VariableInfo>,
99    pub return_type: String,  // Return type from AST
100    pub source_file: String,  // Source file path for distinguishing user code from system headers
101    // Method information for tracking 'this' pointer
102    pub is_method: bool,
103    pub method_qualifier: Option<MethodQualifier>,
104    pub class_name: Option<String>,
105    // Template information
106    pub template_parameters: Vec<String>,  // e.g., ["T", "U"] for template<typename T, typename U>
107    // Phase 1: Lifetime information from annotations
108    pub lifetime_params: HashMap<String, LifetimeParam>,  // e.g., {"a" -> LifetimeParam, "b" -> LifetimeParam}
109    pub param_lifetimes: Vec<Option<ParameterLifetime>>,  // Lifetime for each parameter (indexed by param position)
110    pub return_lifetime: Option<ReturnLifetime>,          // Lifetime of return value
111    pub lifetime_constraints: Vec<LifetimeConstraint>,    // e.g., 'a: 'b (a outlives b)
112}
113
114/// Represents a lifetime parameter declared in the function signature
115/// Example: In `@lifetime: (&'a, &'b) -> &'a where 'a: 'b`, we have lifetime params 'a and 'b
116#[derive(Debug, Clone, PartialEq)]
117pub struct LifetimeParam {
118    pub name: String,  // e.g., "a" (without the apostrophe)
119}
120
121/// Represents the lifetime annotation of a parameter
122#[derive(Debug, Clone, PartialEq)]
123pub struct ParameterLifetime {
124    pub lifetime_name: String,  // e.g., "a" for &'a T
125    pub is_mutable: bool,       // true for &'a mut T, false for &'a T
126    pub is_owned: bool,         // true for "owned" annotation
127}
128
129/// Represents the lifetime annotation of the return value
130#[derive(Debug, Clone, PartialEq)]
131pub struct ReturnLifetime {
132    pub lifetime_name: String,  // e.g., "a" for &'a T
133    pub is_mutable: bool,       // true for &'a mut T, false for &'a T
134    pub is_owned: bool,         // true for "owned" annotation
135}
136
137/// Represents a lifetime constraint (e.g., 'a: 'b means 'a outlives 'b)
138#[derive(Debug, Clone, PartialEq)]
139pub struct LifetimeConstraint {
140    pub longer: String,   // e.g., "a" in 'a: 'b
141    pub shorter: String,  // e.g., "b" in 'a: 'b
142}
143
144#[derive(Debug, Clone)]
145pub struct VariableInfo {
146    #[allow(dead_code)]
147    pub name: String,
148    #[allow(dead_code)]
149    pub ty: VariableType,
150    pub ownership: OwnershipState,
151    #[allow(dead_code)]
152    pub lifetime: Option<Lifetime>,
153    pub is_parameter: bool,  // True if this is a function parameter
154    pub is_static: bool,     // True if this is a static variable
155    pub scope_level: usize,  // Scope depth where variable was declared (0 = function level)
156    pub has_destructor: bool, // True if this is an RAII type (Box, Rc, Arc, etc.)
157    pub declaration_index: usize, // Order of declaration within scope (for drop order)
158}
159
160#[derive(Debug, Clone, PartialEq)]
161#[allow(dead_code)]
162pub enum VariableType {
163    Owned(String),           // Type name
164    Reference(String),       // Referenced type
165    MutableReference(String),
166    UniquePtr(String),
167    SharedPtr(String),
168    Raw(String),
169}
170
171#[derive(Debug, Clone, PartialEq)]
172#[allow(dead_code)]
173pub enum OwnershipState {
174    Owned,
175    Borrowed(BorrowKind),
176    Moved,
177    Uninitialized,
178}
179
180#[derive(Debug, Clone, PartialEq)]
181#[allow(dead_code)]
182pub enum BorrowKind {
183    Immutable,
184    Mutable,
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
188pub struct Lifetime {
189    pub name: String,
190    pub scope_start: usize,
191    pub scope_end: usize,
192}
193
194pub type ControlFlowGraph = DiGraph<BasicBlock, ()>;
195pub type OwnershipGraph = DiGraph<String, OwnershipEdge>;
196
197#[derive(Debug, Clone)]
198pub struct BasicBlock {
199    #[allow(dead_code)]
200    pub id: usize,
201    pub statements: Vec<IrStatement>,
202    #[allow(dead_code)]
203    pub terminator: Option<Terminator>,
204}
205
206#[derive(Debug, Clone)]
207#[allow(dead_code)]
208pub enum IrStatement {
209    Assign {
210        lhs: String,
211        rhs: IrExpression,
212    },
213    Move {
214        from: String,
215        to: String,
216    },
217    Borrow {
218        from: String,
219        to: String,
220        kind: BorrowKind,
221    },
222    CallExpr {
223        func: String,
224        args: Vec<String>,
225        result: Option<String>,
226    },
227    Return {
228        value: Option<String>,
229    },
230    Drop(String),
231    // Scope markers for tracking when blocks begin/end
232    EnterScope,
233    ExitScope,
234    // Loop markers for tracking loop iterations
235    EnterLoop,
236    ExitLoop,
237    // Conditional execution markers
238    If {
239        then_branch: Vec<IrStatement>,
240        else_branch: Option<Vec<IrStatement>>,
241    },
242    // Safety markers
243    EnterUnsafe,
244    ExitUnsafe,
245    // Phase 4: Pack expansion tracking
246    PackExpansion {
247        pack_name: String,
248        operation: String,  // "forward", "move", or "use"
249    },
250    // Variable usage (for checking moved state)
251    UseVariable {
252        var: String,
253        operation: String, // "dereference", "method_call", etc.
254    },
255    // NEW: Field-level operations
256    MoveField {
257        object: String,      // "container"
258        field: String,       // "data"
259        to: String,          // "_moved_data"
260    },
261    UseField {
262        object: String,
263        field: String,
264        operation: String,   // "read", "write", "call"
265    },
266    BorrowField {
267        object: String,
268        field: String,
269        to: String,
270        kind: BorrowKind,
271    },
272    // Implicit drop at scope end (for RAII types)
273    ImplicitDrop {
274        var: String,
275        scope_level: usize,
276        has_destructor: bool,  // True if variable is RAII type (should be marked as moved)
277    },
278    // Lambda expression with captures (for safety checking)
279    LambdaCapture {
280        captures: Vec<LambdaCaptureInfo>,
281    },
282    // Variable declaration (for loop-local tracking)
283    VarDecl {
284        name: String,
285        type_name: String,
286    },
287}
288
289/// Information about a lambda capture
290#[derive(Debug, Clone)]
291pub struct LambdaCaptureInfo {
292    pub name: String,
293    pub is_ref: bool,  // true = reference capture, false = copy capture
294    pub is_this: bool, // true if capturing 'this'
295}
296
297#[derive(Debug, Clone)]
298#[allow(dead_code)]
299pub enum IrExpression {
300    Variable(String),
301    Move(String),
302    Borrow(String, BorrowKind),
303    New(String),  // Allocation
304    Literal(String),  // Literal value assignment (restores ownership)
305}
306
307#[derive(Debug, Clone)]
308#[allow(dead_code)]
309pub enum Terminator {
310    Return(Option<String>),
311    Jump(NodeIndex),
312    Branch {
313        condition: String,
314        then_block: NodeIndex,
315        else_block: NodeIndex,
316    },
317}
318
319#[derive(Debug, Clone)]
320#[allow(dead_code)]
321pub enum OwnershipEdge {
322    Owns,
323    Borrows,
324    MutBorrows,
325}
326
327/// Detect if a type has a non-trivial destructor (RAII type)
328/// These types need implicit drop tracking at scope end
329fn is_raii_type(type_name: &str) -> bool {
330    is_raii_type_with_user_defined(type_name, &std::collections::HashSet::new())
331}
332
333/// RAII Phase 2: Check if type is RAII, including user-defined types with destructors
334pub fn is_raii_type_with_user_defined(type_name: &str, user_defined_raii_types: &std::collections::HashSet<String>) -> bool {
335    // IMPORTANT: References don't have destructors - the referenced object does
336    // So a `std::string&` is NOT an RAII type (it's just an alias)
337    // References should not be marked as having destructors
338    let trimmed = type_name.trim();
339    if trimmed.ends_with('&') || trimmed.ends_with("& ") {
340        return false;  // References never have destructors
341    }
342    // Also check for "const T&" pattern where & comes after the base type
343    if trimmed.contains('&') && !trimmed.contains('<') {
344        // If there's a & but not in template params, it's a reference
345        return false;
346    }
347
348    // Check for Rusty RAII types (with or without namespace prefix)
349    if type_name.starts_with("rusty::Box<") ||
350       type_name.starts_with("Box<") ||  // Without namespace
351       type_name.starts_with("rusty::Rc<") ||
352       type_name.starts_with("Rc<") ||
353       type_name.starts_with("rusty::Arc<") ||
354       type_name.starts_with("Arc<") ||
355       type_name.starts_with("rusty::RefCell<") ||
356       type_name.starts_with("RefCell<") ||
357       type_name.starts_with("rusty::Cell<") ||
358       type_name.starts_with("Cell<") {
359        return true;
360    }
361
362    // Check for standard library RAII types
363    if type_name.starts_with("std::unique_ptr<") ||
364       type_name.starts_with("unique_ptr<") ||  // Without namespace
365       type_name.starts_with("std::shared_ptr<") ||
366       type_name.starts_with("shared_ptr<") ||
367       type_name.starts_with("std::weak_ptr<") ||
368       type_name.starts_with("weak_ptr<") ||
369       type_name.starts_with("std::vector<") ||
370       type_name.starts_with("vector<") ||
371       type_name.starts_with("std::string") ||
372       type_name.starts_with("string") ||
373       type_name.starts_with("std::fstream") ||
374       type_name.starts_with("fstream") ||
375       type_name.starts_with("std::ifstream") ||
376       type_name.starts_with("ifstream") ||
377       type_name.starts_with("std::ofstream") ||
378       type_name.starts_with("ofstream") ||
379       type_name.starts_with("std::mutex") ||
380       type_name.starts_with("mutex") ||
381       type_name.starts_with("std::lock_guard<") ||
382       type_name.starts_with("lock_guard<") ||
383       type_name.starts_with("std::unique_lock<") ||
384       type_name.starts_with("unique_lock<") {
385        return true;
386    }
387
388    // RAII Phase 2: Check user-defined types with destructors
389    // Extract base type name (without template parameters and qualifiers)
390    let base_type = type_name
391        .split('<').next().unwrap_or(type_name)
392        .trim_start_matches("const ")
393        .trim_end_matches('&')
394        .trim_end_matches('*')
395        .trim();
396
397    if user_defined_raii_types.contains(base_type) {
398        return true;
399    }
400
401    // Also check with common namespace prefixes stripped
402    for raii_type in user_defined_raii_types {
403        // Check if type_name contains the RAII type name
404        if type_name.contains(raii_type) {
405            return true;
406        }
407    }
408
409    false
410}
411
412#[allow(dead_code)]
413pub fn build_ir(ast: CppAst) -> Result<IrProgram, String> {
414    let mut functions = Vec::new();
415    let ownership_graph = DiGraph::new();
416
417    // RAII Phase 2: Collect types with user-defined destructors
418    let mut user_defined_raii_types = std::collections::HashSet::new();
419    for class in &ast.classes {
420        if class.has_destructor {
421            user_defined_raii_types.insert(class.name.clone());
422            debug_println!("RAII: Registered user-defined RAII type '{}'", class.name);
423        }
424    }
425
426    for func in ast.functions {
427        let ir_func = convert_function(&func)?;
428        functions.push(ir_func);
429    }
430
431    Ok(IrProgram {
432        functions,
433        ownership_graph,
434        user_defined_raii_types,
435    })
436}
437
438pub fn build_ir_with_safety_context(
439    ast: CppAst,
440    _safety_context: crate::parser::safety_annotations::SafetyContext
441) -> Result<IrProgram, String> {
442    let mut functions = Vec::new();
443    let ownership_graph = DiGraph::new();
444
445    // RAII Phase 2: Collect types with user-defined destructors
446    let mut user_defined_raii_types = std::collections::HashSet::new();
447    for class in &ast.classes {
448        if class.has_destructor {
449            user_defined_raii_types.insert(class.name.clone());
450            debug_println!("RAII: Registered user-defined RAII type '{}'", class.name);
451        }
452    }
453
454    for func in ast.functions {
455        let ir_func = convert_function(&func)?;
456        functions.push(ir_func);
457    }
458
459    Ok(IrProgram {
460        functions,
461        ownership_graph,
462        user_defined_raii_types,
463    })
464}
465
466fn convert_function(func: &crate::parser::Function) -> Result<IrFunction, String> {
467    let mut cfg = DiGraph::new();
468    let mut variables = HashMap::new();
469    let mut current_scope_level = 0; // Track scope depth (0 = function level)
470
471    // Create entry block and convert statements
472    let mut statements = Vec::new();
473
474    for stmt in &func.body {
475        // Convert the statement
476        if let Some(ir_stmts) = convert_statement(stmt, &mut variables, &mut current_scope_level)? {
477            statements.extend(ir_stmts);
478        }
479    }
480    
481    let entry_block = BasicBlock {
482        id: 0,
483        statements,
484        terminator: None,
485    };
486    
487    let _entry_node = cfg.add_node(entry_block);
488    
489    // Process parameters
490    for param in &func.parameters {
491        let (var_type, ownership) = if param.is_unique_ptr {
492            (VariableType::UniquePtr(param.type_name.clone()), OwnershipState::Owned)
493        } else if param.is_reference {
494            if param.is_const {
495                (VariableType::Reference(param.type_name.clone()), 
496                 OwnershipState::Borrowed(BorrowKind::Immutable))
497            } else {
498                (VariableType::MutableReference(param.type_name.clone()),
499                 OwnershipState::Borrowed(BorrowKind::Mutable))
500            }
501        } else {
502            (VariableType::Owned(param.type_name.clone()), OwnershipState::Owned)
503        };
504        
505        let declaration_index = variables.len();  // Parameters declared in order
506        variables.insert(
507            param.name.clone(),
508            VariableInfo {
509                name: param.name.clone(),
510                ty: var_type,
511                ownership,
512                lifetime: None,
513                is_parameter: true,  // This is a parameter
514                is_static: false,    // Parameters are not static
515                scope_level: 0,      // Parameters are at function scope
516                has_destructor: is_raii_type(&param.type_name),
517                declaration_index,   // NEW: Track declaration order
518            },
519        );
520    }
521    
522    Ok(IrFunction {
523        name: func.name.clone(),
524        cfg,
525        variables,
526        return_type: func.return_type.clone(),
527        source_file: func.location.file.clone(),
528        is_method: func.is_method,
529        method_qualifier: func.method_qualifier.clone(),
530        class_name: func.class_name.clone(),
531        template_parameters: func.template_parameters.clone(),
532        // Phase 1: Initialize lifetime fields (will be populated from annotations)
533        lifetime_params: HashMap::new(),
534        param_lifetimes: Vec::new(),
535        return_lifetime: None,
536        lifetime_constraints: Vec::new(),
537    })
538}
539
540// Helper function to get line number from a statement
541#[allow(dead_code)]
542fn get_statement_line(stmt: &crate::parser::Statement) -> Option<u32> {
543    use crate::parser::Statement;
544    match stmt {
545        Statement::Assignment { location, .. } => Some(location.line),
546        Statement::ReferenceBinding { location, .. } => Some(location.line),
547        Statement::FunctionCall { location, .. } => Some(location.line),
548        Statement::If { location, .. } => Some(location.line),
549        Statement::ExpressionStatement { location, .. } => Some(location.line),
550        _ => None,
551    }
552}
553
554/// Extract the source variable from a return expression, handling all expression types.
555/// For complex expressions, this recursively finds the ultimate source variable.
556/// Returns None for literals, function calls, and other expressions with no source variable.
557fn extract_return_source(
558    expr: &crate::parser::Expression,
559    statements: &mut Vec<IrStatement>
560) -> Option<String> {
561    use crate::parser::Expression;
562
563    match expr {
564        Expression::Variable(var) => {
565            // Simple case: return x;
566            Some(var.clone())
567        }
568
569        Expression::Dereference(inner) => {
570            // Dereference: return *ptr;
571            // The source is whatever 'ptr' points to, so recursively extract
572            debug_println!("DEBUG IR: Return dereference expression");
573            extract_return_source(inner, statements)
574        }
575
576        Expression::MemberAccess { object, field } => {
577            // Member access: return obj.field; or return this->ptr;
578            // The source is the object being accessed
579            debug_println!("DEBUG IR: Return member access: {}.{}",
580                if let Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
581                field);
582            extract_return_source(object, statements)
583        }
584
585        Expression::AddressOf(inner) => {
586            // Address-of: return &x;
587            // The source is the variable whose address we're taking
588            debug_println!("DEBUG IR: Return address-of expression");
589            extract_return_source(inner, statements)
590        }
591
592        Expression::Move { inner, .. } => {
593            // Move: return std::move(x);
594            debug_println!("DEBUG IR: Processing Move in return statement");
595            match inner.as_ref() {
596                Expression::Variable(var) => {
597                    debug_println!("DEBUG IR: Return Move(Variable): {}", var);
598                    // Generate Move statement
599                    statements.push(IrStatement::Move {
600                        from: var.clone(),
601                        to: format!("_returned_{}", var),
602                    });
603                    Some(var.clone())
604                }
605                Expression::MemberAccess { object, field } => {
606                    debug_println!("DEBUG IR: Return Move(MemberAccess): {}.{}",
607                        if let Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
608                        field);
609                    if let Expression::Variable(obj_name) = object.as_ref() {
610                        // Generate MoveField statement
611                        statements.push(IrStatement::MoveField {
612                            object: obj_name.clone(),
613                            field: field.clone(),
614                            to: format!("_returned_{}", field),
615                        });
616                        Some(format!("{}.{}", obj_name, field))
617                    } else {
618                        None
619                    }
620                }
621                _ => {
622                    // Move of complex expression - try to extract source
623                    extract_return_source(inner, statements)
624                }
625            }
626        }
627
628        Expression::FunctionCall { name, args } => {
629            // Function call: return foo();
630            // This creates a temporary, but for implicit constructors (e.g., return ptr;)
631            // the variable might be in the arguments
632            debug_println!("DEBUG IR: Return function call: {}", name);
633
634            // Check if any argument is a Move expression (e.g., return Constructor(std::move(x)))
635            // This handles cases like: return std::move(data); where the move is wrapped in a constructor
636            for arg in args.iter() {
637                if let Expression::Move { .. } = arg {
638                    debug_println!("DEBUG IR: Found Move inside function call argument");
639                    // Recursively extract from the Move
640                    return extract_return_source(arg, statements);
641                }
642            }
643
644            if let Some(Expression::Variable(var)) = args.first() {
645                Some(var.clone())
646            } else {
647                None  // Function calls generally create temporaries
648            }
649        }
650
651        Expression::BinaryOp { left, right, op } => {
652            // Binary operation: return a + b;
653            // These create temporaries, but we could track both operands
654            debug_println!("DEBUG IR: Return binary operation: {:?}", op);
655            // For now, return None as these are complex temporaries
656            // Future: could track both left and right as sources
657            None
658        }
659
660        Expression::Literal(_) => {
661            // Literal: return 42;
662            // Literals have no source variable
663            None
664        }
665
666        Expression::StringLiteral(_) => {
667            // String literal: return "hello";
668            // String literals have static lifetime and no source variable to track
669            None
670        }
671
672        Expression::Lambda { .. } => {
673            // Lambda: return [captures]() { ... };
674            // Lambdas are self-contained closures, no direct source variable
675            None
676        }
677
678        Expression::Cast(inner) => {
679            // Cast: return static_cast<T>(x);
680            // The source is whatever is being casted
681            debug_println!("DEBUG IR: Return cast expression");
682            extract_return_source(inner, statements)
683        }
684    }
685}
686
687fn convert_statement(
688    stmt: &crate::parser::Statement,
689    variables: &mut HashMap<String, VariableInfo>,
690    current_scope_level: &mut usize,
691) -> Result<Option<Vec<IrStatement>>, String> {
692    use crate::parser::Statement;
693
694    debug_println!("DEBUG IR: Converting statement: {:?}", match stmt {
695        Statement::VariableDecl(_) => "VariableDecl",
696        Statement::Assignment { .. } => "Assignment",
697        Statement::ReferenceBinding { .. } => "ReferenceBinding",
698        Statement::Return(_) => "Return",
699        Statement::FunctionCall { name, .. } => {
700            debug_println!("DEBUG IR:   FunctionCall name: {}", name);
701            "FunctionCall"
702        },
703        Statement::ExpressionStatement { .. } => "ExpressionStatement",
704        Statement::If { condition, .. } => {
705            debug_println!("DEBUG IR:   If condition: {:?}", condition);
706            "If"
707        },
708        _ => "Other"
709    });
710
711    match stmt {
712        Statement::VariableDecl(var) => {
713            let (var_type, ownership) = if var.is_unique_ptr {
714                (VariableType::UniquePtr(var.type_name.clone()), OwnershipState::Owned)
715            } else if var.is_reference {
716                if var.is_const {
717                    (VariableType::Reference(var.type_name.clone()),
718                     OwnershipState::Uninitialized) // Will be set when bound
719                } else {
720                    (VariableType::MutableReference(var.type_name.clone()),
721                     OwnershipState::Uninitialized)
722                }
723            } else {
724                (VariableType::Owned(var.type_name.clone()), OwnershipState::Owned)
725            };
726            
727            let has_destructor_value = is_raii_type(&var.type_name);
728            let declaration_index = variables.len();  // Current count = declaration order
729            debug_println!("DEBUG IR: VariableDecl '{}': type='{}', has_destructor={}, declaration_index={}",
730                var.name, var.type_name, has_destructor_value, declaration_index);
731
732            variables.insert(
733                var.name.clone(),
734                VariableInfo {
735                    name: var.name.clone(),
736                    ty: var_type,
737                    ownership,
738                    lifetime: None,
739                    is_parameter: false,  // This is a local variable
740                    is_static: var.is_static,  // Propagate static status from parser
741                    scope_level: *current_scope_level,  // Track scope depth
742                    has_destructor: has_destructor_value,
743                    declaration_index,  // NEW: Track declaration order
744                },
745            );
746            // Generate VarDecl IR statement for loop-local tracking
747            Ok(Some(vec![IrStatement::VarDecl {
748                name: var.name.clone(),
749                type_name: var.type_name.clone(),
750            }]))
751        }
752        Statement::ReferenceBinding { name, target, is_mutable, .. } => {
753            let mut statements = Vec::new();
754
755            match target {
756                // Reference to a variable: create a borrow
757                crate::parser::Expression::Variable(target_var) => {
758                    let kind = if *is_mutable {
759                        BorrowKind::Mutable
760                    } else {
761                        BorrowKind::Immutable
762                    };
763
764                    // Update the reference variable's ownership state and type
765                    if let Some(var_info) = variables.get_mut(name) {
766                        var_info.ownership = OwnershipState::Borrowed(kind.clone());
767                        // Update the type to reflect this is a reference
768                        if *is_mutable {
769                            if let VariableType::Owned(type_name) = &var_info.ty {
770                                var_info.ty = VariableType::MutableReference(type_name.clone());
771                            }
772                        } else {
773                            if let VariableType::Owned(type_name) = &var_info.ty {
774                                var_info.ty = VariableType::Reference(type_name.clone());
775                            }
776                        }
777                    }
778
779                    statements.push(IrStatement::Borrow {
780                        from: target_var.clone(),
781                        to: name.clone(),
782                        kind,
783                    });
784                },
785
786                // Reference to function call result: create CallExpr with result
787                crate::parser::Expression::FunctionCall { name: func_name, args } => {
788                    let mut arg_names = Vec::new();
789                    let mut temp_counter = 0;
790
791                    // Process arguments
792                    for arg in args {
793                        match arg {
794                            crate::parser::Expression::Variable(var) => {
795                                arg_names.push(var.clone());
796                            }
797                            crate::parser::Expression::Move { inner, .. } => {
798                                if let crate::parser::Expression::Variable(var) = inner.as_ref() {
799                                    statements.push(IrStatement::Move {
800                                        from: var.clone(),
801                                        to: format!("_moved_{}", var),
802                                    });
803                                    arg_names.push(var.clone());
804                                }
805                            }
806                            // Track literals as temporaries for lifetime analysis
807                            crate::parser::Expression::Literal(lit) => {
808                                let temp_name = format!("_temp_literal_{}_{}", temp_counter, lit);
809                                temp_counter += 1;
810                                arg_names.push(temp_name);
811                            }
812                            // Track string literals - they have static lifetime
813                            crate::parser::Expression::StringLiteral(lit) => {
814                                let temp_name = format!("_temp_string_literal_{}", temp_counter);
815                                temp_counter += 1;
816                                arg_names.push(temp_name);
817                            }
818                            // Track binary expressions as temporaries (e.g., a + b)
819                            crate::parser::Expression::BinaryOp { .. } => {
820                                let temp_name = format!("_temp_expr_{}", temp_counter);
821                                temp_counter += 1;
822                                arg_names.push(temp_name);
823                            }
824                            _ => {}
825                        }
826                    }
827
828                    // Special handling for operator* (dereference)
829                    // When we have: int& r = *box;
830                    // This creates a reference that borrows from the box
831                    if is_dereference_operator(&func_name) {
832                        if let Some(first_arg) = arg_names.first() {
833                            let kind = if *is_mutable {
834                                BorrowKind::Mutable
835                            } else {
836                                BorrowKind::Immutable
837                            };
838
839                            debug_println!("DEBUG IR: ReferenceBinding via operator* creates borrow from '{}'", first_arg);
840
841                            // Create a Borrow from the object being dereferenced
842                            statements.push(IrStatement::Borrow {
843                                from: first_arg.clone(),
844                                to: name.clone(),
845                                kind: kind.clone(),
846                            });
847
848                            // Update the reference variable's ownership state
849                            if let Some(var_info) = variables.get_mut(name) {
850                                var_info.ownership = OwnershipState::Borrowed(kind);
851                            }
852
853                            // Don't create CallExpr for operator* - Borrow is sufficient
854                        } else {
855                            // No arguments - shouldn't happen for operator*
856                            debug_println!("DEBUG IR: operator* with no arguments");
857                        }
858                    } else {
859                        // For other function calls, create CallExpr
860                        statements.push(IrStatement::CallExpr {
861                            func: func_name.clone(),
862                            args: arg_names,
863                            result: Some(name.clone()),
864                        });
865
866                        // Update the reference variable's ownership state
867                        if let Some(var_info) = variables.get_mut(name) {
868                            let kind = if *is_mutable {
869                                BorrowKind::Mutable
870                            } else {
871                                BorrowKind::Immutable
872                            };
873                            var_info.ownership = OwnershipState::Borrowed(kind);
874                        }
875                    }
876                },
877
878                // Reference to a field: create a field borrow
879                // Supports both simple (p.field) and nested (o.inner.field) member access
880                crate::parser::Expression::MemberAccess { object, field } => {
881                    // Use helper to extract full object path for nested access
882                    if let Some((obj_path, final_field)) = extract_member_path(target) {
883                        debug_println!("DEBUG IR: ReferenceBinding to field: {}.{}", obj_path, final_field);
884
885                        let kind = if *is_mutable {
886                            BorrowKind::Mutable
887                        } else {
888                            BorrowKind::Immutable
889                        };
890
891                        // Update the reference variable's ownership state and type
892                        if let Some(var_info) = variables.get_mut(name) {
893                            var_info.ownership = OwnershipState::Borrowed(kind.clone());
894                            // Update the type to reflect this is a reference
895                            if *is_mutable {
896                                if let VariableType::Owned(type_name) = &var_info.ty {
897                                    var_info.ty = VariableType::MutableReference(type_name.clone());
898                                }
899                            } else {
900                                if let VariableType::Owned(type_name) = &var_info.ty {
901                                    var_info.ty = VariableType::Reference(type_name.clone());
902                                }
903                            }
904                        }
905
906                        // Generate BorrowField IR statement with full nested path
907                        statements.push(IrStatement::BorrowField {
908                            object: obj_path,
909                            field: final_field,
910                            to: name.clone(),
911                            kind,
912                        });
913                    } else if let crate::parser::Expression::Variable(obj_name) = object.as_ref() {
914                        // Fallback for simple Variable case
915                        debug_println!("DEBUG IR: ReferenceBinding to field (simple): {}.{}", obj_name, field);
916
917                        let kind = if *is_mutable {
918                            BorrowKind::Mutable
919                        } else {
920                            BorrowKind::Immutable
921                        };
922
923                        if let Some(var_info) = variables.get_mut(name) {
924                            var_info.ownership = OwnershipState::Borrowed(kind.clone());
925                            if *is_mutable {
926                                if let VariableType::Owned(type_name) = &var_info.ty {
927                                    var_info.ty = VariableType::MutableReference(type_name.clone());
928                                }
929                            } else {
930                                if let VariableType::Owned(type_name) = &var_info.ty {
931                                    var_info.ty = VariableType::Reference(type_name.clone());
932                                }
933                            }
934                        }
935
936                        statements.push(IrStatement::BorrowField {
937                            object: obj_name.clone(),
938                            field: field.clone(),
939                            to: name.clone(),
940                            kind,
941                        });
942                    }
943                },
944
945                _ => return Ok(None),
946            }
947
948            Ok(Some(statements))
949        }
950        Statement::Assignment { lhs, rhs, .. } => {
951            // Check if lhs is a dereference: *ptr = value
952            if let crate::parser::Expression::Dereference(ptr_expr) = lhs {
953                // Dereference assignment: *ptr = value
954                if let crate::parser::Expression::Variable(ptr_var) = ptr_expr.as_ref() {
955                    // Extract the RHS variable
956                    let _value_var = match rhs {
957                        crate::parser::Expression::Variable(v) => v.clone(),
958                        _ => return Ok(None), // For now, only handle simple cases
959                    };
960
961                    // Create a UseVariable statement to check that ptr is valid
962                    return Ok(Some(vec![IrStatement::UseVariable {
963                        var: ptr_var.clone(),
964                        operation: "dereference_write".to_string(),
965                    }]));
966                }
967                return Ok(None);
968            }
969
970            // Check if lhs is a function call (e.g., *ptr via operator*)
971            if let crate::parser::Expression::FunctionCall { name, args } = lhs {
972                debug_println!("DEBUG IR: Assignment LHS is function call: {}", name);
973                // Check if this is operator* (dereference for smart pointers)
974                if is_dereference_operator(&name) {
975                    debug_println!("DEBUG IR: Detected operator* on LHS, args: {:?}", args);
976                    // This is a dereference assignment via operator*
977                    // The first argument is the object being dereferenced
978                    if let Some(crate::parser::Expression::Variable(ptr_var)) = args.first() {
979                        debug_println!("DEBUG IR: Creating UseVariable for dereference_write on '{}'", ptr_var);
980                        // Create a UseVariable statement to check that ptr is valid
981                        return Ok(Some(vec![IrStatement::UseVariable {
982                            var: ptr_var.clone(),
983                            operation: "dereference_write (via operator*)".to_string(),
984                        }]));
985                    }
986                }
987                // Other method calls on LHS are not supported for now
988                debug_println!("DEBUG IR: Unsupported function call on LHS");
989                return Ok(None);
990            }
991
992            // Check if LHS is a field access (e.g., this.value = 42)
993            if let crate::parser::Expression::MemberAccess { object, field } = lhs {
994                debug_println!("DEBUG IR: Field write assignment: {}.{} = ...",
995                    if let crate::parser::Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
996                    field);
997
998                if let crate::parser::Expression::Variable(obj_name) = object.as_ref() {
999                    // Generate UseField statement for write operation
1000                    return Ok(Some(vec![
1001                        IrStatement::UseField {
1002                            object: obj_name.clone(),
1003                            field: field.clone(),
1004                            operation: "write".to_string(),
1005                        }
1006                    ]));
1007                } else {
1008                    return Ok(None);
1009                }
1010            }
1011
1012            // Regular assignment (not a dereference)
1013            let lhs_var = match lhs {
1014                crate::parser::Expression::Variable(v) => v,
1015                _ => return Ok(None), // Skip complex lhs for now
1016            };
1017
1018            // SPECIAL CASE: Check if LHS is an RAII type (Box, Rc, Arc, etc.)
1019            // For RAII types, assignment is operator= which:
1020            // 1. Drops the old value (checked if borrowed)
1021            // 2. Moves new value in
1022            // This applies when RHS is Move or creates a new object
1023            let lhs_is_raii = if let Some(lhs_info) = variables.get(lhs_var) {
1024                match &lhs_info.ty {
1025                    VariableType::Owned(type_name) => is_raii_type(type_name),
1026                    _ => false,
1027                }
1028            } else {
1029                false
1030            };
1031
1032            // Track if we need to prepend a Drop check for RAII reassignment
1033            let mut prepend_drop = false;
1034
1035            if lhs_is_raii {
1036                debug_println!("DEBUG IR: Assignment to RAII type '{}', this is operator= (drops old value)", lhs_var);
1037
1038                // For RAII types, assignment is operator= which drops the old value.
1039                // We need to check if LHS is borrowed before allowing this.
1040
1041                // Handle Move expression: box = std::move(other)
1042                if let crate::parser::Expression::Move { inner, .. } = rhs {
1043                    match inner.as_ref() {
1044                        crate::parser::Expression::Variable(from_var) => {
1045                            debug_println!("DEBUG IR: RAII assignment with std::move: generating Move from '{}' to '{}'", from_var, lhs_var);
1046
1047                            // Generate Move statement - this will check if LHS is borrowed!
1048                            // Move already handles the drop implicitly
1049                            return Ok(Some(vec![IrStatement::Move {
1050                                from: from_var.clone(),
1051                                to: lhs_var.clone(),
1052                            }]));
1053                        }
1054                        _ => {
1055                            // Move of complex expression - continue to regular handling
1056                            debug_println!("DEBUG IR: Move of complex expression");
1057                        }
1058                    }
1059                }
1060
1061                // For other cases (constructor calls like Box::make), we need to:
1062                // 1. Generate a Drop check (to verify not borrowed)
1063                // 2. Generate the actual assignment IR
1064                debug_println!("DEBUG IR: Will prepend Drop check for RAII assignment");
1065                prepend_drop = true;
1066            }
1067
1068            let assignment_ir = match rhs {
1069                crate::parser::Expression::Dereference(ptr_expr) => {
1070                    // Dereference read: lhs = *ptr
1071                    if let crate::parser::Expression::Variable(ptr_var) = ptr_expr.as_ref() {
1072                        // Create a UseVariable statement to check that ptr is valid
1073                        Ok(Some(vec![IrStatement::UseVariable {
1074                            var: ptr_var.clone(),
1075                            operation: "dereference_read".to_string(),
1076                        }]))
1077                    } else {
1078                        Ok(None)
1079                    }
1080                }
1081                crate::parser::Expression::Variable(rhs_var) => {
1082                    // Check if this is a move or a copy
1083                    if let Some(rhs_info) = variables.get(rhs_var) {
1084                        match &rhs_info.ty {
1085                            VariableType::UniquePtr(_) => {
1086                                // This is a move
1087                                Ok(Some(vec![IrStatement::Move {
1088                                    from: rhs_var.clone(),
1089                                    to: lhs_var.clone(),
1090                                }]))
1091                            }
1092                            _ => {
1093                                // Regular assignment (copy)
1094                                Ok(Some(vec![IrStatement::Assign {
1095                                    lhs: lhs_var.clone(),
1096                                    rhs: IrExpression::Variable(rhs_var.clone()),
1097                                }]))
1098                            }
1099                        }
1100                    } else {
1101                        Ok(None)
1102                    }
1103                }
1104                // NEW: Handle field access (not a move) - including nested fields
1105                crate::parser::Expression::MemberAccess { .. } => {
1106                    // Use helper to extract full path for nested member access
1107                    if let Some((obj_path, field_name)) = extract_member_path(rhs) {
1108                        debug_println!("DEBUG IR: Processing MemberAccess read from '{}.{}'", obj_path, field_name);
1109                        Ok(Some(vec![
1110                            IrStatement::UseField {
1111                                object: obj_path.clone(),
1112                                field: field_name.clone(),
1113                                operation: "read".to_string(),
1114                            },
1115                            IrStatement::Assign {
1116                                lhs: lhs_var.clone(),
1117                                rhs: IrExpression::Variable(format!("{}.{}", obj_path, field_name)),
1118                            }
1119                        ]))
1120                    } else {
1121                        debug_println!("DEBUG IR: MemberAccess could not be parsed");
1122                        Ok(None)
1123                    }
1124                }
1125                crate::parser::Expression::Move { inner, .. } => {
1126                    debug_println!("DEBUG IR: Processing Move expression in assignment");
1127                    // This is an explicit std::move call
1128                    match inner.as_ref() {
1129                        crate::parser::Expression::Variable(var) => {
1130                            debug_println!("DEBUG IR: Creating IrStatement::Move from '{}' to '{}'", var, lhs_var);
1131                            // Transfer type from source if needed
1132                            let source_type = variables.get(var).map(|info| info.ty.clone());
1133                            if let Some(var_info) = variables.get_mut(lhs_var) {
1134                                if let Some(ty) = source_type {
1135                                    var_info.ty = ty;
1136                                }
1137                            }
1138                            Ok(Some(vec![IrStatement::Move {
1139                                from: var.clone(),
1140                                to: lhs_var.clone(),
1141                            }]))
1142                        }
1143                        // NEW: Handle std::move(obj.field) including nested fields
1144                        crate::parser::Expression::MemberAccess { .. } => {
1145                            // Use helper to extract full path for nested member access
1146                            if let Some((obj_path, field_name)) = extract_member_path(inner.as_ref()) {
1147                                debug_println!("DEBUG IR: Creating MoveField for field '{}' of object '{}'", field_name, obj_path);
1148                                Ok(Some(vec![IrStatement::MoveField {
1149                                    object: obj_path,
1150                                    field: field_name,
1151                                    to: lhs_var.clone(),
1152                                }]))
1153                            } else {
1154                                debug_println!("DEBUG IR: MemberAccess could not be parsed");
1155                                Ok(None)
1156                            }
1157                        }
1158                        _ => {
1159                            debug_println!("DEBUG IR: Move expression doesn't contain a variable or member access");
1160                            Ok(None)
1161                        }
1162                    }
1163                }
1164                crate::parser::Expression::FunctionCall { name, args } => {
1165                    // Convert function call arguments, handling moves
1166                    let mut statements = Vec::new();
1167                    let mut arg_names = Vec::new();
1168                    let mut temp_counter = 0;
1169
1170                    // Check if this is a method call (operator* or other methods)
1171                    // Methods can be: qualified (Class::method), operators (operator*, operator bool), or have :: in name
1172                    let is_method_call = name.contains("::") || name.starts_with("operator");
1173
1174                    for (i, arg) in args.iter().enumerate() {
1175                        match arg {
1176                            // Track literals as temporaries for lifetime analysis
1177                            crate::parser::Expression::Literal(lit) => {
1178                                let temp_name = format!("_temp_literal_{}_{}", temp_counter, lit);
1179                                temp_counter += 1;
1180                                arg_names.push(temp_name);
1181                            }
1182                            // Track string literals - they have static lifetime
1183                            crate::parser::Expression::StringLiteral(lit) => {
1184                                let temp_name = format!("_temp_string_literal_{}", temp_counter);
1185                                temp_counter += 1;
1186                                arg_names.push(temp_name);
1187                            }
1188                            // Track binary expressions as temporaries (e.g., a + b)
1189                            crate::parser::Expression::BinaryOp { .. } => {
1190                                let temp_name = format!("_temp_expr_{}", temp_counter);
1191                                temp_counter += 1;
1192                                arg_names.push(temp_name);
1193                            }
1194                            crate::parser::Expression::Variable(var) => {
1195                                // For method calls, the first arg is the receiver object
1196                                if is_method_call && i == 0 {
1197                                    // Check if this is operator* (dereference)
1198                                    if is_dereference_operator(&name) {
1199                                        statements.push(IrStatement::UseVariable {
1200                                            var: var.clone(),
1201                                            operation: "dereference_read (via operator*)".to_string(),
1202                                        });
1203                                    } else {
1204                                        // Other method calls also use the receiver
1205                                        statements.push(IrStatement::UseVariable {
1206                                            var: var.clone(),
1207                                            operation: format!("call method '{}'", name),
1208                                        });
1209                                    }
1210                                }
1211                                arg_names.push(var.clone());
1212                            }
1213                            crate::parser::Expression::Move { inner, .. } => {
1214                                // Handle std::move in constructor/function arguments
1215                                debug_println!("DEBUG IR: Processing Move in assignment RHS function call");
1216                                match inner.as_ref() {
1217                                    crate::parser::Expression::Variable(var) => {
1218                                        debug_println!("DEBUG IR: Move(Variable) in assignment: {}", var);
1219
1220                                        // CRITICAL FIX: When Move is the receiver of a method call (first argument),
1221                                        // use the temporary as the receiver instead of the original variable.
1222                                        // This allows calling && methods on rvalue expressions like std::move(c).consume()
1223                                        let temp_name = format!("_moved_{}", var);
1224                                        statements.push(IrStatement::Move {
1225                                            from: var.clone(),
1226                                            to: temp_name.clone(),
1227                                        });
1228
1229                                        if is_method_call && i == 0 {
1230                                            // Use the temporary as the receiver for rvalue method calls
1231                                            debug_println!("DEBUG IR: Move as method receiver - using temporary '{}' instead of '{}'", temp_name, var);
1232                                            arg_names.push(temp_name);
1233                                        } else {
1234                                            // For non-receiver arguments, use the original variable name
1235                                            arg_names.push(var.clone());
1236                                        }
1237                                    }
1238                                    crate::parser::Expression::MemberAccess { .. } => {
1239                                        // Use helper to extract full path for nested member access
1240                                        if let Some((obj_path, field_name)) = extract_member_path(inner.as_ref()) {
1241                                            debug_println!("DEBUG IR: Move(MemberAccess) in assignment: {}.{}", obj_path, field_name);
1242                                            statements.push(IrStatement::MoveField {
1243                                                object: obj_path.clone(),
1244                                                field: field_name.clone(),
1245                                                to: lhs_var.clone(),  // Move to the LHS variable
1246                                            });
1247                                            arg_names.push(format!("{}.{}", obj_path, field_name));
1248                                        }
1249                                    }
1250                                    _ => {}
1251                                }
1252                            }
1253                            crate::parser::Expression::FunctionCall { name: recv_name, args: recv_args } if is_method_call && i == 0 => {
1254                                // Receiver is a method call itself (e.g., ptr->method() where ptr-> is operator->)
1255                                debug_println!("DEBUG IR: Receiver is FunctionCall: {}", recv_name);
1256
1257                                // Check if this is operator-> (pointer dereference for method call)
1258                                if is_member_access_operator(&recv_name) {
1259                                    // Extract the actual pointer variable from operator-> args
1260                                    for recv_arg in recv_args {
1261                                        if let crate::parser::Expression::Variable(var) = recv_arg {
1262                                            debug_println!("DEBUG IR: Found pointer variable in operator->: {}", var);
1263                                            statements.push(IrStatement::UseVariable {
1264                                                var: var.clone(),
1265                                                operation: format!("call method '{}' via operator->", name),
1266                                            });
1267                                        }
1268                                    }
1269                                }
1270                                arg_names.push(format!("_result_of_{}", recv_name));
1271                            }
1272                            crate::parser::Expression::Move { inner, .. } => {
1273                                if let crate::parser::Expression::Variable(var) = inner.as_ref() {
1274                                    // Mark as moved before the call
1275                                    statements.push(IrStatement::Move {
1276                                        from: var.clone(),
1277                                        to: format!("_temp_move_{}", var),
1278                                    });
1279                                    arg_names.push(var.clone());
1280                                }
1281                            }
1282                            // NEW: Handle field access as function argument (including nested)
1283                            crate::parser::Expression::MemberAccess { .. } => {
1284                                // Use helper to extract full path for nested member access
1285                                if let Some((obj_path, field_name)) = extract_member_path(arg) {
1286                                    debug_println!("DEBUG IR: MemberAccess as function argument in assignment: {}.{}", obj_path, field_name);
1287                                    // Generate UseField statement to check if field is valid
1288                                    statements.push(IrStatement::UseField {
1289                                        object: obj_path.clone(),
1290                                        field: field_name.clone(),
1291                                        operation: "use in function call".to_string(),
1292                                    });
1293                                    arg_names.push(format!("{}.{}", obj_path, field_name));
1294                                }
1295                            }
1296                            _ => {}
1297                        }
1298                    }
1299
1300                    statements.push(IrStatement::CallExpr {
1301                        func: name.clone(),
1302                        args: arg_names,
1303                        result: Some(lhs_var.clone()),
1304                    });
1305
1306                    Ok(Some(statements))
1307                }
1308                // REASSIGNMENT FIX: Handle literal assignments (e.g., x = 42)
1309                // This generates IR so that ownership can be properly restored
1310                crate::parser::Expression::Literal(value) => {
1311                    debug_println!("DEBUG IR: Literal assignment: {} = {}", lhs_var, value);
1312                    Ok(Some(vec![IrStatement::Assign {
1313                        lhs: lhs_var.clone(),
1314                        rhs: IrExpression::Literal(value.clone()),
1315                    }]))
1316                }
1317                // String literal assignment (e.g., const char* s = "hello")
1318                // String literals have static lifetime - this is safe
1319                crate::parser::Expression::StringLiteral(value) => {
1320                    debug_println!("DEBUG IR: String literal assignment: {} = \"{}\"", lhs_var, value);
1321                    Ok(Some(vec![IrStatement::Assign {
1322                        lhs: lhs_var.clone(),
1323                        rhs: IrExpression::Literal(value.clone()),  // Treat as literal for IR
1324                    }]))
1325                }
1326                // Lambda expression: generate LambdaCapture statement for safety checking
1327                crate::parser::Expression::Lambda { captures } => {
1328                    debug_println!("DEBUG IR: Lambda assignment: {} = [captures]", lhs_var);
1329                    let capture_infos: Vec<LambdaCaptureInfo> = captures.iter().map(|c| {
1330                        use crate::parser::ast_visitor::LambdaCaptureKind;
1331                        match c {
1332                            LambdaCaptureKind::DefaultRef => LambdaCaptureInfo {
1333                                name: "<default>".to_string(),
1334                                is_ref: true,
1335                                is_this: false,
1336                            },
1337                            LambdaCaptureKind::DefaultCopy => LambdaCaptureInfo {
1338                                name: "<default>".to_string(),
1339                                is_ref: false,
1340                                is_this: false,
1341                            },
1342                            LambdaCaptureKind::ByRef(name) => LambdaCaptureInfo {
1343                                name: name.clone(),
1344                                is_ref: true,
1345                                is_this: false,
1346                            },
1347                            LambdaCaptureKind::ByCopy(name) => LambdaCaptureInfo {
1348                                name: name.clone(),
1349                                is_ref: false,
1350                                is_this: false,
1351                            },
1352                            LambdaCaptureKind::Init { name, is_move } => LambdaCaptureInfo {
1353                                name: name.clone(),
1354                                is_ref: false, // Init captures are by value
1355                                is_this: false,
1356                            },
1357                            LambdaCaptureKind::This => LambdaCaptureInfo {
1358                                name: "this".to_string(),
1359                                is_ref: true, // 'this' capture is a pointer, essentially by-ref
1360                                is_this: true,
1361                            },
1362                            LambdaCaptureKind::ThisCopy => LambdaCaptureInfo {
1363                                name: "this".to_string(),
1364                                is_ref: false, // *this capture is by value
1365                                is_this: true,
1366                            },
1367                        }
1368                    }).collect();
1369
1370                    Ok(Some(vec![IrStatement::LambdaCapture {
1371                        captures: capture_infos,
1372                    }]))
1373                }
1374                _ => Ok(None)
1375            };
1376
1377            // If we need to prepend a Drop check for RAII reassignment, do it now
1378            if prepend_drop {
1379                debug_println!("DEBUG IR: Prepending Drop check to assignment IR");
1380                match assignment_ir {
1381                    Ok(Some(mut stmts)) => {
1382                        // Prepend Drop to the existing statements
1383                        stmts.insert(0, IrStatement::Drop(lhs_var.clone()));
1384                        Ok(Some(stmts))
1385                    }
1386                    Ok(None) => {
1387                        // No assignment IR generated, just return Drop
1388                        Ok(Some(vec![IrStatement::Drop(lhs_var.clone())]))
1389                    }
1390                    Err(e) => Err(e)
1391                }
1392            } else {
1393                assignment_ir
1394            }
1395        }
1396        Statement::FunctionCall { name, args, .. } => {
1397            debug_println!("DEBUG IR: Processing FunctionCall statement: {} with {} args", name, args.len());
1398            // Standalone function call (no assignment)
1399            let mut statements = Vec::new();
1400            let mut arg_names = Vec::new();
1401            let mut temp_counter = 0;
1402
1403            // Check if this is a method call (has :: or is an operator)
1404            // Methods can be: qualified (Class::method), operators (operator*, operator bool), or have :: in name
1405            let is_method_call = name.contains("::") || name.starts_with("operator");
1406
1407            // Special handling for operator= (assignment operators)
1408            // box1 = std::move(box2) becomes operator=(box1, Move(box2))
1409            // We need to treat this as: Move { from: box2, to: box1 }
1410            if is_assignment_operator(&name) {
1411                debug_println!("DEBUG IR: Detected operator= call");
1412                if args.len() == 2 {
1413                    // First arg is LHS (destination), second is RHS (source)
1414                    if let crate::parser::Expression::Variable(lhs) = &args[0] {
1415                        // Check if LHS is an RAII type
1416                        let lhs_is_raii = if let Some(lhs_info) = variables.get(lhs) {
1417                            match &lhs_info.ty {
1418                                VariableType::Owned(type_name) => is_raii_type(type_name),
1419                                _ => false,
1420                            }
1421                        } else {
1422                            false
1423                        };
1424
1425                        // Handle Move RHS
1426                        if let crate::parser::Expression::Move { inner: rhs_inner, .. } = &args[1] {
1427                            debug_println!("DEBUG IR: operator= with Move: {} = Move(...)", lhs);
1428                            if let crate::parser::Expression::Variable(rhs) = rhs_inner.as_ref() {
1429                                debug_println!("DEBUG IR: Creating Move from '{}' to '{}' for operator=", rhs, lhs);
1430                                return Ok(Some(vec![IrStatement::Move {
1431                                    from: rhs.clone(),
1432                                    to: lhs.clone(),
1433                                }]));
1434                            }
1435                        }
1436
1437                        // For RAII types with non-move RHS, we need to check borrows before drop
1438                        if lhs_is_raii {
1439                            debug_println!("DEBUG IR: operator= on RAII type '{}' - generating Drop check", lhs);
1440                            // Generate Drop check - the FunctionCall itself will be processed below
1441                            statements.push(IrStatement::Drop(lhs.clone()));
1442                        }
1443                    }
1444                }
1445            }
1446
1447            // Process arguments, looking for std::move
1448            for (i, arg) in args.iter().enumerate() {
1449                match arg {
1450                    crate::parser::Expression::Variable(var) => {
1451                        // For method calls, the first arg is the receiver object
1452                        if is_method_call && i == 0 {
1453                            // Check if this is operator* (dereference)
1454                            let operation = if is_dereference_operator(&name) {
1455                                "dereference (via operator*)".to_string()
1456                            } else {
1457                                format!("call method '{}'", name)
1458                            };
1459
1460                            statements.push(IrStatement::UseVariable {
1461                                var: var.clone(),
1462                                operation,
1463                            });
1464                        }
1465                        arg_names.push(var.clone());
1466                    }
1467                    crate::parser::Expression::Move { inner, .. } => {
1468                        // Handle std::move in function arguments
1469                        match inner.as_ref() {
1470                            crate::parser::Expression::Variable(var) => {
1471                                debug_println!("DEBUG IR: Move(Variable) as direct argument: {}", var);
1472
1473                                // CRITICAL FIX: When Move is the receiver of a method call (first argument),
1474                                // use the temporary as the receiver instead of the original variable.
1475                                // This allows calling && methods on rvalue expressions like std::move(c).consume()
1476                                let temp_name = format!("_moved_{}", var);
1477                                statements.push(IrStatement::Move {
1478                                    from: var.clone(),
1479                                    to: temp_name.clone(),
1480                                });
1481
1482                                if is_method_call && i == 0 {
1483                                    // Use the temporary as the receiver for rvalue method calls
1484                                    debug_println!("DEBUG IR: Move as method receiver - using temporary '{}' instead of '{}'", temp_name, var);
1485                                    arg_names.push(temp_name);
1486                                } else {
1487                                    // For non-receiver arguments, use the original variable name
1488                                    arg_names.push(var.clone());
1489                                }
1490                            }
1491                            crate::parser::Expression::MemberAccess { .. } => {
1492                                // Use helper to extract full path for nested member access
1493                                if let Some((obj_path, field_name)) = extract_member_path(inner.as_ref()) {
1494                                    debug_println!("DEBUG IR: Move(MemberAccess) as direct argument: {}.{}", obj_path, field_name);
1495                                    statements.push(IrStatement::MoveField {
1496                                        object: obj_path.clone(),
1497                                        field: field_name.clone(),
1498                                        to: format!("_moved_{}", field_name),
1499                                    });
1500                                    arg_names.push(format!("{}.{}", obj_path, field_name));
1501                                }
1502                            }
1503                            _ => {}
1504                        }
1505                    }
1506                    crate::parser::Expression::FunctionCall { name: inner_name, args: inner_args } => {
1507                        debug_println!("DEBUG IR: Nested FunctionCall in argument: {}", inner_name);
1508
1509                        // Check if this is the receiver of a method call (i == 0)
1510                        if is_method_call && i == 0 {
1511                            // Check if this is operator-> (pointer dereference for method call)
1512                            if is_member_access_operator(&inner_name) {
1513                                // Extract the actual pointer variable from operator-> args
1514                                for inner_arg in inner_args {
1515                                    if let crate::parser::Expression::Variable(var) = inner_arg {
1516                                        debug_println!("DEBUG IR: Found pointer variable in operator->: {}", var);
1517                                        statements.push(IrStatement::UseVariable {
1518                                            var: var.clone(),
1519                                            operation: format!("call method '{}' via operator->", name),
1520                                        });
1521                                    }
1522                                }
1523                            }
1524                        }
1525
1526                        // Recursively check for moves in nested function call
1527                        for inner_arg in inner_args {
1528                            if let crate::parser::Expression::Move { inner: move_inner, .. } = inner_arg {
1529                                match move_inner.as_ref() {
1530                                    crate::parser::Expression::Variable(var) => {
1531                                        debug_println!("DEBUG IR: Found Move(Variable) in nested call: {}", var);
1532                                        statements.push(IrStatement::Move {
1533                                            from: var.clone(),
1534                                            to: format!("_moved_{}", var),
1535                                        });
1536                                    }
1537                                    crate::parser::Expression::MemberAccess { .. } => {
1538                                        // Use helper to extract full path for nested member access
1539                                        if let Some((obj_path, field_name)) = extract_member_path(move_inner.as_ref()) {
1540                                            debug_println!("DEBUG IR: Found Move(MemberAccess) in nested call: {}.{}", obj_path, field_name);
1541                                            statements.push(IrStatement::MoveField {
1542                                                object: obj_path,
1543                                                field: field_name.clone(),
1544                                                to: format!("_moved_{}", field_name),
1545                                            });
1546                                        }
1547                                    }
1548                                    _ => {}
1549                                }
1550                            }
1551                        }
1552                        // Use placeholder for nested call result
1553                        arg_names.push(format!("_result_of_{}", inner_name));
1554                    }
1555                    // NEW: Handle field access as function argument (including nested)
1556                    crate::parser::Expression::MemberAccess { .. } => {
1557                        // Use helper to extract full path for nested member access
1558                        if let Some((obj_path, field_name)) = extract_member_path(arg) {
1559                            debug_println!("DEBUG IR: MemberAccess as function argument: {}.{}", obj_path, field_name);
1560                            // Generate UseField statement to check if field is valid
1561                            statements.push(IrStatement::UseField {
1562                                object: obj_path.clone(),
1563                                field: field_name.clone(),
1564                                operation: "use in function call".to_string(),
1565                            });
1566                            arg_names.push(format!("{}.{}", obj_path, field_name));
1567                        }
1568                    }
1569                    // Track literals as temporaries for lifetime analysis
1570                    crate::parser::Expression::Literal(lit) => {
1571                        let temp_name = format!("_temp_literal_{}_{}", temp_counter, lit);
1572                        temp_counter += 1;
1573                        arg_names.push(temp_name);
1574                    }
1575                    // Track string literals - they have static lifetime
1576                    crate::parser::Expression::StringLiteral(lit) => {
1577                        let temp_name = format!("_temp_string_literal_{}", temp_counter);
1578                        temp_counter += 1;
1579                        arg_names.push(temp_name);
1580                    }
1581                    // Track binary expressions as temporaries (e.g., a + b)
1582                    crate::parser::Expression::BinaryOp { .. } => {
1583                        let temp_name = format!("_temp_expr_{}", temp_counter);
1584                        temp_counter += 1;
1585                        arg_names.push(temp_name);
1586                    }
1587                    _ => {}
1588                }
1589            }
1590
1591            statements.push(IrStatement::CallExpr {
1592                func: name.clone(),
1593                args: arg_names,
1594                result: None,
1595            });
1596
1597            Ok(Some(statements))
1598        }
1599        Statement::Return(expr) => {
1600            let mut statements = Vec::new();
1601
1602            let value = expr.as_ref().and_then(|e| {
1603                extract_return_source(e, &mut statements)
1604            });
1605
1606            statements.push(IrStatement::Return { value });
1607            Ok(Some(statements))
1608        }
1609        Statement::EnterScope => {
1610            *current_scope_level += 1;
1611            debug_println!("DEBUG IR: EnterScope - now at level {}", current_scope_level);
1612            Ok(Some(vec![IrStatement::EnterScope]))
1613        }
1614        Statement::ExitScope => {
1615            debug_println!("DEBUG IR: ExitScope - leaving level {}", current_scope_level);
1616            debug_println!("DEBUG IR: Total variables: {}", variables.len());
1617            for (name, info) in variables.iter() {
1618                debug_println!("DEBUG IR:   Variable '{}': scope_level={}, has_destructor={}, is_static={}",
1619                    name, info.scope_level, info.has_destructor, info.is_static);
1620            }
1621
1622            // Find ALL variables declared at this scope level (including references)
1623            // We need to clear borrows for all variables, not just RAII types
1624            let mut vars_to_drop: Vec<(String, usize, bool)> = variables
1625                .iter()
1626                .filter(|(_, info)| {
1627                    info.scope_level == *current_scope_level &&
1628                    !info.is_static  // Static variables are never dropped
1629                })
1630                .map(|(name, info)| (name.clone(), info.declaration_index, info.has_destructor))
1631                .collect();
1632
1633            // Sort by reverse declaration order (highest index first)
1634            // This ensures variables drop in reverse order of declaration
1635            vars_to_drop.sort_by(|a, b| b.1.cmp(&a.1));
1636
1637            debug_println!("DROP ORDER: Processing {} variables at scope end in reverse declaration order", vars_to_drop.len());
1638            for (name, decl_idx, has_dest) in &vars_to_drop {
1639                debug_println!("DROP ORDER:   '{}' (declaration_index={}, has_destructor={})", name, decl_idx, has_dest);
1640            }
1641
1642            // Create ImplicitDrop statements in reverse declaration order
1643            // This clears borrows for ALL variables, and marks RAII types as moved
1644            let mut statements = Vec::new();
1645            for (var, _, has_dest) in vars_to_drop {
1646                debug_println!("DEBUG IR: Inserting ImplicitDrop for '{}' at scope level {} (has_destructor={})",
1647                    var, current_scope_level, has_dest);
1648                statements.push(IrStatement::ImplicitDrop {
1649                    var,
1650                    scope_level: *current_scope_level,
1651                    has_destructor: has_dest,
1652                });
1653            }
1654
1655            // Add the ExitScope marker after the drops
1656            statements.push(IrStatement::ExitScope);
1657
1658            *current_scope_level = current_scope_level.saturating_sub(1);
1659            Ok(Some(statements))
1660        }
1661        Statement::EnterLoop => {
1662            Ok(Some(vec![IrStatement::EnterLoop]))
1663        }
1664        Statement::ExitLoop => {
1665            Ok(Some(vec![IrStatement::ExitLoop]))
1666        }
1667        Statement::EnterUnsafe => {
1668            Ok(Some(vec![IrStatement::EnterUnsafe]))
1669        }
1670        Statement::ExitUnsafe => {
1671            Ok(Some(vec![IrStatement::ExitUnsafe]))
1672        }
1673        Statement::If { condition, then_branch, else_branch, .. } => {
1674            // Convert if statement to IR
1675            // First, process the condition (which might contain uses like `if (ptr)`)
1676            let mut condition_ir = Vec::new();
1677
1678            // Extract uses from the condition expression
1679            match condition {
1680                crate::parser::Expression::FunctionCall { name, args } => {
1681                    // Method call in condition (e.g., if (ptr.operator bool()))
1682                    let is_method_call = name.contains("::") || name.starts_with("operator");
1683
1684                    for (i, arg) in args.iter().enumerate() {
1685                        if let crate::parser::Expression::Variable(var) = arg {
1686                            // For method calls, first arg is the receiver
1687                            if is_method_call && i == 0 {
1688                                debug_println!("DEBUG IR: Creating UseVariable for '{}' in condition (method: {})", var, name);
1689                                condition_ir.push(IrStatement::UseVariable {
1690                                    var: var.clone(),
1691                                    operation: format!("call method '{}' in condition", name),
1692                                });
1693                            }
1694                        }
1695                    }
1696                }
1697                crate::parser::Expression::Variable(var) => {
1698                    // Direct variable use in condition
1699                    condition_ir.push(IrStatement::UseVariable {
1700                        var: var.clone(),
1701                        operation: "use in condition".to_string(),
1702                    });
1703                }
1704                _ => {
1705                    // Other expression types - ignore for now
1706                }
1707            }
1708
1709            // Convert then branch
1710            let mut then_ir = Vec::new();
1711            for stmt in then_branch {
1712                if let Some(ir_stmts) = convert_statement(stmt, variables, current_scope_level)? {
1713                    then_ir.extend(ir_stmts);
1714                }
1715            }
1716
1717            // Convert else branch if present
1718            let else_ir = if let Some(else_stmts) = else_branch {
1719                let mut else_ir = Vec::new();
1720                for stmt in else_stmts {
1721                    if let Some(ir_stmts) = convert_statement(stmt, variables, current_scope_level)? {
1722                        else_ir.extend(ir_stmts);
1723                    }
1724                }
1725                Some(else_ir)
1726            } else {
1727                None
1728            };
1729
1730            // Return condition uses followed by the If statement
1731            let mut result = condition_ir;
1732            result.push(IrStatement::If {
1733                then_branch: then_ir,
1734                else_branch: else_ir,
1735            });
1736            Ok(Some(result))
1737        }
1738        Statement::ExpressionStatement { expr, .. } => {
1739            // Handle expression statements (dereference, method calls, assignments, etc.)
1740            match expr {
1741                crate::parser::Expression::Dereference(inner) => {
1742                    // Extract the variable being dereferenced
1743                    if let crate::parser::Expression::Variable(var) = inner.as_ref() {
1744                        Ok(Some(vec![IrStatement::UseVariable {
1745                            var: var.clone(),
1746                            operation: "dereference".to_string(),
1747                        }]))
1748                    } else {
1749                        Ok(None)
1750                    }
1751                }
1752                crate::parser::Expression::AddressOf(inner) => {
1753                    // Address-of doesn't use the value, so no moved-state check needed
1754                    Ok(None)
1755                }
1756                // Handle assignment expressions (e.g., value = 42;)
1757                crate::parser::Expression::BinaryOp { left, op, right } if op == "=" => {
1758                    debug_println!("DEBUG IR: ExpressionStatement assignment: op={}", op);
1759
1760                    // Check if LHS is a field access (e.g., this.value = 42)
1761                    if let crate::parser::Expression::MemberAccess { object, field } = left.as_ref() {
1762                        debug_println!("DEBUG IR: ExpressionStatement field write: {}.{} = ...",
1763                            if let crate::parser::Expression::Variable(obj) = object.as_ref() { obj } else { "complex" },
1764                            field);
1765
1766                        if let crate::parser::Expression::Variable(obj_name) = object.as_ref() {
1767                            // Generate UseField statement for write operation
1768                            return Ok(Some(vec![
1769                                IrStatement::UseField {
1770                                    object: obj_name.clone(),
1771                                    field: field.clone(),
1772                                    operation: "write".to_string(),
1773                                }
1774                            ]));
1775                        }
1776                    }
1777
1778                    // For other assignments, fall through
1779                    Ok(None)
1780                }
1781                _ => Ok(None),
1782            }
1783        }
1784        Statement::PackExpansion { pack_name, operation, .. } => {
1785            // Phase 4: Convert pack expansion to IR
1786            debug_println!("DEBUG IR: PackExpansion: pack='{}', operation='{}'", pack_name, operation);
1787            Ok(Some(vec![IrStatement::PackExpansion {
1788                pack_name: pack_name.clone(),
1789                operation: operation.clone(),
1790            }]))
1791        }
1792        _ => Ok(None),
1793    }
1794}
1795
1796#[cfg(test)]
1797mod tests {
1798    use super::*;
1799    use crate::parser::{Function, Variable, SourceLocation};
1800
1801    fn create_test_function(name: &str) -> Function {
1802        Function {
1803            name: name.to_string(),
1804            parameters: vec![],
1805            return_type: "void".to_string(),
1806            body: vec![],
1807            location: SourceLocation {
1808                file: "test.cpp".to_string(),
1809                line: 1,
1810                column: 1,
1811            },
1812            is_method: false,
1813            method_qualifier: None,
1814            class_name: None,
1815            template_parameters: vec![],
1816            safety_annotation: None,
1817            has_explicit_safety_annotation: false,
1818        }
1819    }
1820
1821    fn create_test_variable(name: &str, type_name: &str, is_unique_ptr: bool) -> Variable {
1822        Variable {
1823            name: name.to_string(),
1824            type_name: type_name.to_string(),
1825            is_reference: false,
1826            is_pointer: false,
1827            is_const: false,
1828            is_unique_ptr,
1829            is_shared_ptr: false,
1830            is_static: false,
1831            is_mutable: false,
1832            location: SourceLocation {
1833                file: "test.cpp".to_string(),
1834                line: 1,
1835                column: 1,
1836            },
1837            is_pack: false,
1838            pack_element_type: None,
1839        }
1840    }
1841
1842    #[test]
1843    fn test_build_empty_ir() {
1844        let ast = crate::parser::CppAst::new();
1845        let result = build_ir(ast);
1846        
1847        assert!(result.is_ok());
1848        let ir = result.unwrap();
1849        assert_eq!(ir.functions.len(), 0);
1850    }
1851
1852    #[test]
1853    fn test_build_ir_with_function() {
1854        let mut ast = crate::parser::CppAst::new();
1855        ast.functions.push(create_test_function("test_func"));
1856        
1857        let result = build_ir(ast);
1858        assert!(result.is_ok());
1859        
1860        let ir = result.unwrap();
1861        assert_eq!(ir.functions.len(), 1);
1862        assert_eq!(ir.functions[0].name, "test_func");
1863    }
1864
1865    #[test]
1866    fn test_variable_type_classification() {
1867        let unique_var = create_test_variable("ptr", "std::unique_ptr<int>", true);
1868        let mut ast = crate::parser::CppAst::new();
1869        let mut func = create_test_function("test");
1870        func.parameters.push(unique_var);
1871        ast.functions.push(func);
1872        
1873        let result = build_ir(ast);
1874        assert!(result.is_ok());
1875        
1876        let ir = result.unwrap();
1877        let var_info = ir.functions[0].variables.get("ptr").unwrap();
1878        assert!(matches!(var_info.ty, VariableType::UniquePtr(_)));
1879    }
1880
1881    #[test]
1882    fn test_ownership_state_initialization() {
1883        let var = create_test_variable("x", "int", false);
1884        let mut ast = crate::parser::CppAst::new();
1885        let mut func = create_test_function("test");
1886        func.parameters.push(var);
1887        ast.functions.push(func);
1888        
1889        let result = build_ir(ast);
1890        assert!(result.is_ok());
1891        
1892        let ir = result.unwrap();
1893        let var_info = ir.functions[0].variables.get("x").unwrap();
1894        assert_eq!(var_info.ownership, OwnershipState::Owned);
1895    }
1896
1897    #[test]
1898    fn test_lifetime_creation() {
1899        let lifetime = Lifetime {
1900            name: "a".to_string(),
1901            scope_start: 0,
1902            scope_end: 10,
1903        };
1904
1905        assert_eq!(lifetime.name, "a");
1906        assert_eq!(lifetime.scope_start, 0);
1907        assert_eq!(lifetime.scope_end, 10);
1908    }
1909}
1910
1911// Phase 1: Conversion functions from parsed annotations to IR lifetime types
1912
1913/// Convert LifetimeAnnotation to ParameterLifetime for IR
1914fn convert_param_lifetime(annotation: &crate::parser::annotations::LifetimeAnnotation) -> Option<ParameterLifetime> {
1915    use crate::parser::annotations::LifetimeAnnotation;
1916
1917    match annotation {
1918        LifetimeAnnotation::Ref(lifetime_name) => {
1919            Some(ParameterLifetime {
1920                lifetime_name: lifetime_name.clone(),
1921                is_mutable: false,
1922                is_owned: false,
1923            })
1924        }
1925        LifetimeAnnotation::MutRef(lifetime_name) => {
1926            Some(ParameterLifetime {
1927                lifetime_name: lifetime_name.clone(),
1928                is_mutable: true,
1929                is_owned: false,
1930            })
1931        }
1932        LifetimeAnnotation::Owned => {
1933            Some(ParameterLifetime {
1934                lifetime_name: String::new(),  // No specific lifetime for owned
1935                is_mutable: false,
1936                is_owned: true,
1937            })
1938        }
1939        LifetimeAnnotation::Lifetime(_) => {
1940            // Bare lifetime parameter like 'a - not applicable to parameter type
1941            None
1942        }
1943    }
1944}
1945
1946/// Convert LifetimeAnnotation to ReturnLifetime for IR
1947fn convert_return_lifetime(annotation: &crate::parser::annotations::LifetimeAnnotation) -> Option<ReturnLifetime> {
1948    use crate::parser::annotations::LifetimeAnnotation;
1949
1950    match annotation {
1951        LifetimeAnnotation::Ref(lifetime_name) => {
1952            Some(ReturnLifetime {
1953                lifetime_name: lifetime_name.clone(),
1954                is_mutable: false,
1955                is_owned: false,
1956            })
1957        }
1958        LifetimeAnnotation::MutRef(lifetime_name) => {
1959            Some(ReturnLifetime {
1960                lifetime_name: lifetime_name.clone(),
1961                is_mutable: true,
1962                is_owned: false,
1963            })
1964        }
1965        LifetimeAnnotation::Owned => {
1966            Some(ReturnLifetime {
1967                lifetime_name: String::new(),  // No specific lifetime for owned
1968                is_mutable: false,
1969                is_owned: true,
1970            })
1971        }
1972        LifetimeAnnotation::Lifetime(_) => {
1973            // Bare lifetime parameter like 'a - not applicable to return type
1974            None
1975        }
1976    }
1977}
1978
1979/// Populate IrFunction lifetime fields from FunctionSignature annotations
1980pub fn populate_lifetime_info(
1981    ir_func: &mut IrFunction,
1982    signature: &crate::parser::annotations::FunctionSignature
1983) {
1984    debug_println!("DEBUG IR LIFETIME: Populating lifetime info for function '{}'", ir_func.name);
1985
1986    // Extract all unique lifetime names from parameters and return type
1987    let mut lifetime_names = std::collections::HashSet::new();
1988
1989    // Collect lifetime names from parameters
1990    for param_lifetime_opt in &signature.param_lifetimes {
1991        if let Some(param_lifetime) = param_lifetime_opt {
1992            if let Some(name) = extract_lifetime_name_from_annotation(param_lifetime) {
1993                lifetime_names.insert(name);
1994            }
1995        }
1996    }
1997
1998    // Collect lifetime name from return type
1999    if let Some(return_lifetime) = &signature.return_lifetime {
2000        if let Some(name) = extract_lifetime_name_from_annotation(return_lifetime) {
2001            lifetime_names.insert(name);
2002        }
2003    }
2004
2005    // Collect lifetime names from bounds
2006    for bound in &signature.lifetime_bounds {
2007        lifetime_names.insert(bound.longer.clone());
2008        lifetime_names.insert(bound.shorter.clone());
2009    }
2010
2011    // Create LifetimeParam entries
2012    for name in lifetime_names {
2013        debug_println!("DEBUG IR LIFETIME:   Lifetime parameter: '{}'", name);
2014        ir_func.lifetime_params.insert(
2015            name.clone(),
2016            LifetimeParam { name }
2017        );
2018    }
2019
2020    // Convert parameter lifetimes
2021    for param_lifetime_opt in &signature.param_lifetimes {
2022        let converted = param_lifetime_opt.as_ref()
2023            .and_then(|lt| convert_param_lifetime(lt));
2024
2025        if let Some(ref param_lt) = converted {
2026            debug_println!("DEBUG IR LIFETIME:   Parameter lifetime: '{}' (mutable={}, owned={})",
2027                param_lt.lifetime_name, param_lt.is_mutable, param_lt.is_owned);
2028        }
2029
2030        ir_func.param_lifetimes.push(converted);
2031    }
2032
2033    // Convert return lifetime
2034    ir_func.return_lifetime = signature.return_lifetime.as_ref()
2035        .and_then(|lt| convert_return_lifetime(lt));
2036
2037    if let Some(ref ret_lt) = ir_func.return_lifetime {
2038        debug_println!("DEBUG IR LIFETIME:   Return lifetime: '{}' (mutable={}, owned={})",
2039            ret_lt.lifetime_name, ret_lt.is_mutable, ret_lt.is_owned);
2040    }
2041
2042    // Convert lifetime constraints
2043    for bound in &signature.lifetime_bounds {
2044        debug_println!("DEBUG IR LIFETIME:   Lifetime constraint: '{}': '{}'", bound.longer, bound.shorter);
2045        ir_func.lifetime_constraints.push(LifetimeConstraint {
2046            longer: bound.longer.clone(),
2047            shorter: bound.shorter.clone(),
2048        });
2049    }
2050
2051    debug_println!("DEBUG IR LIFETIME: Populated {} lifetime params, {} param lifetimes, {} constraints",
2052        ir_func.lifetime_params.len(), ir_func.param_lifetimes.len(), ir_func.lifetime_constraints.len());
2053}
2054
2055/// Extract lifetime name from a LifetimeAnnotation
2056fn extract_lifetime_name_from_annotation(annotation: &crate::parser::annotations::LifetimeAnnotation) -> Option<String> {
2057    use crate::parser::annotations::LifetimeAnnotation;
2058
2059    match annotation {
2060        LifetimeAnnotation::Ref(name) => Some(name.clone()),
2061        LifetimeAnnotation::MutRef(name) => Some(name.clone()),
2062        LifetimeAnnotation::Lifetime(name) => Some(name.trim_start_matches('\'').to_string()),
2063        LifetimeAnnotation::Owned => None,
2064    }
2065}