1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Rust Coercion Rules - Determines when Rust auto-derefs/auto-copies
//!
//! Rust has complex coercion rules:
//! - Auto-deref for method calls, field access, comparisons
//! - Auto-copy for Copy types in many contexts
//! - Explicit deref/clone needed in other contexts
//!
//! This module encodes these rules systematically.
use crate::analyzer::OwnershipMode;
use crate::codegen::rust::copy_semantics::DerefContext;
pub struct RustCoercionRules;
impl RustCoercionRules {
/// Check if Rust auto-derefs in this context
pub fn rust_auto_derefs(context: DerefContext) -> bool {
matches!(
context,
DerefContext::Comparison
| DerefContext::MethodCall
| DerefContext::FieldAccess
| DerefContext::BinaryOp
)
}
/// Check if Rust auto-copies in this context (for Copy types)
pub fn rust_auto_copies(context: DerefContext, is_copy: bool) -> bool {
is_copy
&& matches!(
context,
DerefContext::Comparison
| DerefContext::BinaryOp
| DerefContext::StructLiteral
| DerefContext::FunctionArg
)
}
/// Determine required coercion to go from source to target ownership
pub fn required_coercion(
source_ownership: OwnershipMode,
target_ownership: OwnershipMode,
is_copy: bool,
context: DerefContext,
) -> Coercion {
use OwnershipMode::*;
match (source_ownership, target_ownership, is_copy) {
// Source and target match - no coercion
(Owned, Owned, _) => Coercion::None,
(Borrowed, Borrowed, _) => Coercion::None,
(MutBorrowed, MutBorrowed, _) => Coercion::None,
// Borrowed → Owned
(Borrowed, Owned, true) if Self::rust_auto_copies(context, true) => Coercion::None,
(Borrowed, Owned, true) => Coercion::Deref,
(Borrowed, Owned, false) => Coercion::Clone,
(MutBorrowed, Owned, true) if Self::rust_auto_copies(context, true) => Coercion::None,
(MutBorrowed, Owned, true) => Coercion::Deref,
(MutBorrowed, Owned, false) => Coercion::Clone,
// Owned → Borrowed
(Owned, Borrowed, _) => Coercion::Borrow,
(Owned, MutBorrowed, _) => Coercion::BorrowMut,
// Borrow ↔ MutBorrow (generally invalid, but handle gracefully)
(Borrowed, MutBorrowed, _) => Coercion::None, // Can't upgrade &T to &mut T
(MutBorrowed, Borrowed, _) => Coercion::None, // Can downgrade &mut T to &T implicitly
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Coercion {
None,
Deref,
Clone,
Borrow,
BorrowMut,
}
impl Coercion {
/// Apply this coercion to a generated expression string.
/// Handles idempotency: won't double-borrow, double-clone, etc.
pub fn apply(self, expr_str: &mut String) {
match self {
Coercion::None => {}
Coercion::Deref => {
if !expr_str.starts_with('*') {
*expr_str = format!("*{}", expr_str);
}
}
Coercion::Clone => {
if !expr_str.ends_with(".clone()") {
*expr_str = format!("{}.clone()", expr_str);
}
}
Coercion::Borrow => {
if !expr_str.starts_with('&') {
*expr_str = format!("&{}", expr_str);
}
}
Coercion::BorrowMut => {
if !expr_str.starts_with("&mut ") {
if expr_str.starts_with('&') {
*expr_str = format!("&mut {}", &expr_str[1..]);
} else {
*expr_str = format!("&mut {}", expr_str);
}
}
}
}
}
}