diff --git a/crates/perry-runtime/src/object/delete_rest.rs b/crates/perry-runtime/src/object/delete_rest.rs index 9613b259f..3aeaae7ea 100644 --- a/crates/perry-runtime/src/object/delete_rest.rs +++ b/crates/perry-runtime/src/object/delete_rest.rs @@ -179,12 +179,21 @@ pub extern "C" fn js_object_delete_field( } } // A class-declaration prototype object: instance accessors (`get x()`) - // and methods live in the class vtable, not the keys_array, so the scan - // below would "succeed vacuously" while the member stayed visible to - // hasOwnProperty / getOwnPropertyDescriptor. Record the key as deleted - // so those reflective paths agree it is gone (test262 verifyProperty's + // live ONLY in the class vtable, so the scan below would "succeed + // vacuously" while the accessor stayed visible to hasOwnProperty / + // getOwnPropertyDescriptor. Record the key as deleted so those + // reflective paths agree it is gone (test262 verifyProperty's // `configurable` check: `delete obj[name]` then assert the key absent — // class/definition/{getters,setters}-prop-desc). + // + // Instance METHODS are different: `install_class_decl_prototype_method_fields` + // plants each one as a REAL keys_array data field on the prototype + // object (writable:true, enumerable:false, configurable:true). Marking + // the vtable key deleted is necessary but NOT sufficient — we must also + // fall through to the keys scan to drop that real field, or + // hasOwnProperty keeps finding the method via `own_key_present` and + // verifyProperty fails "m descriptor should be configurable" (#5441, + // ~760 generated language/{statements,expressions}/class tests). if let Some(cid) = super::class_registry::class_id_for_decl_prototype_object(obj as usize) { if let Some(name) = super::has_own_helpers::str_from_string_header(key) { if name != "constructor" @@ -192,7 +201,9 @@ pub extern "C" fn js_object_delete_field( || super::native_module::class_has_own_method(cid, name)) { super::class_registry::class_mark_key_deleted(cid, name); - return 1; + // Accessors have no keys_array entry, so the scan below is a + // vacuous success for them; methods DO, so fall through to + // remove it. Either way, don't early-return. } } }