Skip to content

Commit 8718dc4

Browse files
committed
mangle_name for __ prefixed members
1 parent f893da6 commit 8718dc4

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

crates/vm/src/builtins/type.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,25 +1185,27 @@ impl Constructor for PyType {
11851185

11861186
if let Some(ref slots) = heaptype_slots {
11871187
let mut offset = base_member_count;
1188+
let class_name = typ.name().to_string();
11881189
for member in slots.as_slice() {
1190+
// Apply name mangling for private attributes (__x -> _ClassName__x)
1191+
let mangled_name = mangle_name(&class_name, member.as_str());
11891192
let member_def = PyMemberDef {
1190-
name: member.to_string(),
1193+
name: mangled_name.clone(),
11911194
kind: MemberKind::ObjectEx,
11921195
getter: MemberGetter::Offset(offset),
11931196
setter: MemberSetter::Offset(offset),
11941197
doc: None,
11951198
};
1199+
let attr_name = vm.ctx.intern_str(mangled_name.as_str());
11961200
let member_descriptor: PyRef<PyMemberDescriptor> =
11971201
vm.ctx.new_pyref(PyMemberDescriptor {
11981202
common: PyDescriptorOwned {
11991203
typ: typ.clone(),
1200-
name: vm.ctx.intern_str(member.as_str()),
1204+
name: attr_name,
12011205
qualname: PyRwLock::new(None),
12021206
},
12031207
member: member_def,
12041208
});
1205-
1206-
let attr_name = vm.ctx.intern_str(member.as_str());
12071209
// __slots__ attributes always get a member descriptor
12081210
// (this overrides any inherited attribute from MRO)
12091211
typ.set_attr(attr_name, member_descriptor.into());
@@ -1793,6 +1795,18 @@ fn best_base<'a>(bases: &'a [PyTypeRef], vm: &VirtualMachine) -> PyResult<&'a Py
17931795
Ok(base.unwrap())
17941796
}
17951797

1798+
/// Apply Python name mangling for private attributes.
1799+
/// `__x` becomes `_ClassName__x` if inside a class.
1800+
fn mangle_name(class_name: &str, name: &str) -> String {
1801+
// Only mangle names starting with __ and not ending with __
1802+
if !name.starts_with("__") || name.ends_with("__") || name.contains('.') {
1803+
return name.to_string();
1804+
}
1805+
// Strip leading underscores from class name
1806+
let class_name = class_name.trim_start_matches('_');
1807+
format!("_{}{}", class_name, name)
1808+
}
1809+
17961810
#[cfg(test)]
17971811
mod tests {
17981812
use super::*;

0 commit comments

Comments
 (0)