Skip to content

Feature: Implement CanBeHeldWeakly Symbol support for FinalizationRegistry #5253

@workonlly

Description

@workonlly

Feature Description

Summary

Implement CanBeHeldWeakly Symbol support for FinalizationRegistry unregister token handling.

Currently, FinalizationRegistry has TODO markers for Symbol support in its weak checks (core/engine/src/builtins/finalization_registry/mod.rs around lines 225, 249, 307). This issue proposes implementing Symbol handling for register and unregister token validation so behavior matches ECMAScript rules for non-registered Symbols.

Specification Intent

The ECMAScript abstract operation CanBeHeldWeakly(v) returns true when:

  1. v is an Object.
  2. v is a Symbol and Symbol.keyFor(v) is undefined (a non-registered Symbol).
  3. Otherwise, false.

For this issue, this logic must be applied to the unregisterToken validation in both FinalizationRegistry.prototype.register and FinalizationRegistry.prototype.unregister.

Motivation

  • Improves ECMAScript conformance for FinalizationRegistry.
  • Closes a clear runtime correctness gap in weak-reference related APIs.
  • Demonstrates robust handling of Symbol lifecycles in GC-observable features.

Proposed Scope

  • Add Symbol branch to unregisterToken validation in register.
  • Add Symbol branch to unregisterToken validation in unregister.
  • Reject registered Symbols from Symbol.for(...) for unregisterToken.
  • Accept non-registered Symbols from Symbol(...).
  • Keep existing Object behavior unchanged.

Acceptance Criteria

  • register accepts Object, non-registered Symbol, or undefined as unregisterToken.
  • register throws TypeError for registered Symbol unregisterToken.
  • unregister accepts Object or non-registered Symbol.
  • unregister throws TypeError for registered Symbol.
  • Existing FinalizationRegistry behavior and tests remain passing.

Test Plan

Add and pass tests in tests.rs:

  • register/unregister with Symbol(local) removes registration successfully.
  • register with Symbol.for(global) as token throws TypeError.
  • unregister with Symbol.for(global) throws TypeError.
  • Existing object-token tests continue to pass.

Example code
This JavaScript code should execute according to the updated CanBeHeldWeakly semantics:

const registry = new FinalizationRegistry(heldValue => {});

let localSymbol = Symbol("local");
let globalSymbol = Symbol.for("global");

// 1. Should succeed most importntly (non-registered symbol)
registry.register({}, "val", localSymbol);
registry.unregister(localSymbol);

// 2. Should throw TypeError (registered symbol cannot be held weakly) focus on it
try {
    registry.register({}, "val", globalSymbol);
} catch (e) {
    console.log(e.name); // Expected: TypeError
}

// 3. Should throw TypeError check it 
try {
    registry.unregister(globalSymbol);
} catch (e) {
    console.log(e.name); // Expected: TypeError
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions