Merge pull request #81 from moe-charm/copilot/fix-80
Fix SocketBox state separation issue - method call clone state loss
This commit is contained in:
@ -56,13 +56,25 @@ pub struct SocketBox {
|
||||
|
||||
impl Clone for SocketBox {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
eprintln!("🔄 SOCKETBOX CLONE: Creating clone of Socket ID={}", self.base.id);
|
||||
eprintln!("🔄 Original Arc pointer = {:p}", &self.is_server);
|
||||
eprintln!("🔄 Original Arc data pointer = {:p}", self.is_server.as_ref());
|
||||
eprintln!("🔄 Original Arc strong_count = {}", std::sync::Arc::strong_count(&self.is_server));
|
||||
|
||||
let cloned = Self {
|
||||
base: BoxBase::new(), // New unique ID for clone (for debugging/identity)
|
||||
listener: Arc::clone(&self.listener), // Share the same listener
|
||||
stream: Arc::clone(&self.stream), // Share the same stream
|
||||
is_server: Arc::clone(&self.is_server), // Share the same state container
|
||||
is_connected: Arc::clone(&self.is_connected), // Share the same state container
|
||||
}
|
||||
};
|
||||
|
||||
eprintln!("🔄 New clone ID = {}", cloned.base.id);
|
||||
eprintln!("🔄 New Arc pointer = {:p}", &cloned.is_server);
|
||||
eprintln!("🔄 New Arc data pointer = {:p}", cloned.is_server.as_ref());
|
||||
eprintln!("🔄 New Arc strong_count = {}", std::sync::Arc::strong_count(&cloned.is_server));
|
||||
|
||||
cloned
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,6 +370,7 @@ impl SocketBox {
|
||||
eprintln!("🔥 SOCKETBOX DEBUG: is_server() called");
|
||||
eprintln!("🔥 Socket ID = {}", self.base.id);
|
||||
eprintln!("🔥 Arc pointer = {:p}", &self.is_server);
|
||||
eprintln!("🔥 Arc data pointer = {:p}", self.is_server.as_ref());
|
||||
|
||||
match self.is_server.lock() {
|
||||
Ok(is_server_guard) => {
|
||||
|
||||
@ -467,28 +467,69 @@ impl NyashInterpreter {
|
||||
// These methods modify the SocketBox internal state, so we need to update
|
||||
// the stored variable/field to ensure subsequent accesses get the updated state
|
||||
if matches!(method, "bind" | "connect" | "close") {
|
||||
eprintln!("🔧 DEBUG: Stateful method '{}' called, updating stored instance", method);
|
||||
let updated_instance = socket_box.clone();
|
||||
eprintln!("🔧 DEBUG: Updated instance created with ID={}", updated_instance.box_id());
|
||||
|
||||
match object {
|
||||
ASTNode::Variable { name, .. } => {
|
||||
eprintln!("🔧 DEBUG: Updating local variable '{}'", name);
|
||||
// Handle local variables
|
||||
if let Some(stored_var) = self.local_vars.get_mut(name) {
|
||||
eprintln!("🔧 DEBUG: Found local variable '{}', updating from id={} to id={}",
|
||||
name, stored_var.box_id(), updated_instance.box_id());
|
||||
*stored_var = Arc::new(updated_instance);
|
||||
} else {
|
||||
eprintln!("🔧 DEBUG: Local variable '{}' not found", name);
|
||||
}
|
||||
},
|
||||
ASTNode::FieldAccess { object: field_obj, field, .. } => {
|
||||
eprintln!("🔧 DEBUG: Updating field access '{}'", field);
|
||||
// Handle StaticBox fields like me.server
|
||||
if let ASTNode::Variable { name, .. } = field_obj.as_ref() {
|
||||
if name == "me" {
|
||||
if let Ok(me_instance) = self.resolve_variable("me") {
|
||||
if let Some(instance) = (*me_instance).as_any().downcast_ref::<InstanceBox>() {
|
||||
let _ = instance.set_field(field, Arc::new(updated_instance));
|
||||
match field_obj.as_ref() {
|
||||
ASTNode::Variable { name, .. } => {
|
||||
eprintln!("🔧 DEBUG: Field object is variable '{}'", name);
|
||||
if name == "me" {
|
||||
eprintln!("🔧 DEBUG: Updating me.{} (via variable)", field);
|
||||
if let Ok(me_instance) = self.resolve_variable("me") {
|
||||
eprintln!("🔧 DEBUG: Resolved 'me' instance id={}", me_instance.box_id());
|
||||
if let Some(instance) = (*me_instance).as_any().downcast_ref::<InstanceBox>() {
|
||||
eprintln!("🔧 DEBUG: me is InstanceBox, setting field '{}' to updated instance id={}", field, updated_instance.box_id());
|
||||
let result = instance.set_field(field, Arc::new(updated_instance));
|
||||
eprintln!("🔧 DEBUG: set_field result: {:?}", result);
|
||||
} else {
|
||||
eprintln!("🔧 DEBUG: me is not an InstanceBox, type: {}", me_instance.type_name());
|
||||
}
|
||||
} else {
|
||||
eprintln!("🔧 DEBUG: Failed to resolve 'me'");
|
||||
}
|
||||
} else {
|
||||
eprintln!("🔧 DEBUG: Field object is not 'me', it's '{}'", name);
|
||||
}
|
||||
},
|
||||
ASTNode::Me { .. } => {
|
||||
eprintln!("🔧 DEBUG: Field object is Me node, updating me.{}", field);
|
||||
if let Ok(me_instance) = self.resolve_variable("me") {
|
||||
eprintln!("🔧 DEBUG: Resolved 'me' instance id={}", me_instance.box_id());
|
||||
if let Some(instance) = (*me_instance).as_any().downcast_ref::<InstanceBox>() {
|
||||
eprintln!("🔧 DEBUG: me is InstanceBox, setting field '{}' to updated instance id={}", field, updated_instance.box_id());
|
||||
let result = instance.set_field(field, Arc::new(updated_instance));
|
||||
eprintln!("🔧 DEBUG: set_field result: {:?}", result);
|
||||
} else {
|
||||
eprintln!("🔧 DEBUG: me is not an InstanceBox, type: {}", me_instance.type_name());
|
||||
}
|
||||
} else {
|
||||
eprintln!("🔧 DEBUG: Failed to resolve 'me'");
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
eprintln!("🔧 DEBUG: Field object is not a variable or me, type: {:?}", field_obj);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
_ => {
|
||||
eprintln!("🔧 DEBUG: Object type not handled: {:?}", object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
34
test_debug_clone_state.nyash
Normal file
34
test_debug_clone_state.nyash
Normal file
@ -0,0 +1,34 @@
|
||||
# Diagnostic test to understand clone state sharing
|
||||
static box Main {
|
||||
init { console, socket1, socket2 }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🔬 Clone State Diagnostic Test")
|
||||
|
||||
# Create original SocketBox
|
||||
me.socket1 = new SocketBox()
|
||||
|
||||
# Set state via bind
|
||||
local bindResult = me.socket1.bind("127.0.0.1", 19001)
|
||||
me.console.log("✅ bind() result: " + bindResult.toString())
|
||||
|
||||
# Check state immediately
|
||||
local isServer1 = me.socket1.isServer()
|
||||
me.console.log("🔍 socket1.isServer() after bind: " + isServer1.toString())
|
||||
|
||||
# Now check toString to see the socket ID
|
||||
local socketStr1 = me.socket1.toString()
|
||||
me.console.log("🆔 socket1 ID after bind: " + socketStr1)
|
||||
|
||||
# Check state again to see if we get the same socket ID
|
||||
local isServer2 = me.socket1.isServer()
|
||||
me.console.log("🔍 socket1.isServer() second call: " + isServer2.toString())
|
||||
|
||||
# Check toString again
|
||||
local socketStr2 = me.socket1.toString()
|
||||
me.console.log("🆔 socket1 ID second call: " + socketStr2)
|
||||
|
||||
return "DIAGNOSTIC_COMPLETE"
|
||||
}
|
||||
}
|
||||
26
test_direct_clone.nyash
Normal file
26
test_direct_clone.nyash
Normal file
@ -0,0 +1,26 @@
|
||||
# Isolate the Arc sharing issue
|
||||
static box Main {
|
||||
init { console }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🔬 Direct Clone Test")
|
||||
|
||||
# Create socket and bind
|
||||
local socket1 = new SocketBox()
|
||||
local bindResult = socket1.bind("127.0.0.1", 19777)
|
||||
me.console.log("✅ Bind result: " + bindResult.toString())
|
||||
|
||||
# Clone the socket manually
|
||||
local socket2 = socket1
|
||||
|
||||
# Check if clone has the same state
|
||||
local isServer1 = socket1.isServer()
|
||||
local isServer2 = socket2.isServer()
|
||||
|
||||
me.console.log("🔍 socket1.isServer(): " + isServer1.toString())
|
||||
me.console.log("🔍 socket2.isServer(): " + isServer2.toString())
|
||||
|
||||
return "DIRECT_CLONE_TEST"
|
||||
}
|
||||
}
|
||||
29
test_field_arc_sharing.nyash
Normal file
29
test_field_arc_sharing.nyash
Normal file
@ -0,0 +1,29 @@
|
||||
# Test Arc sharing for field access
|
||||
static box Main {
|
||||
init { console, server }
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.log("🔬 Field Access Arc Sharing Test")
|
||||
|
||||
# Store socket in field
|
||||
me.server = new SocketBox()
|
||||
me.console.log("✅ Created me.server")
|
||||
|
||||
# Test 1: Multiple field accesses
|
||||
local str1 = me.server.toString()
|
||||
me.console.log("📊 First field access: " + str1)
|
||||
|
||||
local str2 = me.server.toString()
|
||||
me.console.log("📊 Second field access: " + str2)
|
||||
|
||||
# Test 2: State change via field access
|
||||
local bindResult = me.server.bind("127.0.0.1", 19888)
|
||||
me.console.log("✅ Bind via field access: " + bindResult.toString())
|
||||
|
||||
local isServer = me.server.isServer()
|
||||
me.console.log("🔍 isServer via field access: " + isServer.toString())
|
||||
|
||||
return "FIELD_ACCESS_ARC_TEST"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user