From bdd39251b7e400ad915e9fd3123a3152ee2278e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 24 Aug 2026 20:58:50 +0200 Subject: [PATCH 1/2] fix(runtime): inherit Object prototype on class instances --- changelog.d/class-instance-object-prototype-read.md | 4 ++++ .../src/object/field_get_set/accessors.rs | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 changelog.d/class-instance-object-prototype-read.md diff --git a/changelog.d/class-instance-object-prototype-read.md b/changelog.d/class-instance-object-prototype-read.md new file mode 100644 index 0000000000..87a3f5c314 --- /dev/null +++ b/changelog.d/class-instance-object-prototype-read.md @@ -0,0 +1,4 @@ +Fixed inherited `Object.prototype` property reads on declared class instances. +Classes without their own `toString` or `valueOf` now resolve the default +methods instead of reporting the properties as present while reading them as +`undefined`, restoring ordinary string coercion such as `String(new C())`. diff --git a/crates/perry-runtime/src/object/field_get_set/accessors.rs b/crates/perry-runtime/src/object/field_get_set/accessors.rs index de75ce90db..5f5059da14 100644 --- a/crates/perry-runtime/src/object/field_get_set/accessors.rs +++ b/crates/perry-runtime/src/object/field_get_set/accessors.rs @@ -240,7 +240,16 @@ pub(crate) unsafe fn ordinary_object_prototype_property_value( return None; } let class_id = (*obj).class_id; - if class_id != 0 && !is_anon_shape_class_id(class_id) { + // Declared ES class instances have a registered class id, but still end + // their implicit prototype chain at Object.prototype. Their class + // methods/accessors have already been consulted before this fallback, so + // a miss must remain eligible for Object.prototype (including user-added + // properties). Keep excluding unregistered native/synthetic class ids: + // those object kinds resolve their own intrinsic prototype chains. + if class_id != 0 + && !is_anon_shape_class_id(class_id) + && !super::super::class_registry::is_class_id_registered(class_id) + { return None; } default_object_prototype_property_value(obj as usize, key) From 046dae6ef58e764f88e3d168ca9cc99556f60292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 24 Aug 2026 20:59:15 +0200 Subject: [PATCH 2/2] chore: align changelog with PR 8780 --- ...otype-read.md => 8780-class-instance-object-prototype-read.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{class-instance-object-prototype-read.md => 8780-class-instance-object-prototype-read.md} (100%) diff --git a/changelog.d/class-instance-object-prototype-read.md b/changelog.d/8780-class-instance-object-prototype-read.md similarity index 100% rename from changelog.d/class-instance-object-prototype-read.md rename to changelog.d/8780-class-instance-object-prototype-read.md