Skip to content

Commit eeed4fe

Browse files
committed
Fix WeakMap/WeakSet to pass 115 Test262 tests (176/176)
- Rewrite WeakMap/WeakSet constructors to use spec-compliant iterator protocol with .set()/.add() calls - Validate set/add callable before iterating; throw TypeError if not a function - Add new_target parameter for Reflect.construct support - Set constructor length/name properties (non-enumerable, non-writable, configurable) - Set Function.prototype as constructor [[Prototype]] - Mark prototype property non-enumerable, non-writable, non-configurable - Add Symbol.toStringTag on WeakMap.prototype and WeakSet.prototype - Change raise_eval_error to raise_type_error in dispatch and instance methods - Return this (wrapper object) from set/add instead of raw Value::WeakMap/WeakSet - Relax strict argument count checks to match spec behavior - Register WeakMap/WeakSet method lengths in all three function-length tables - Add CI workflow entries for built-ins/Uint8Array through built-ins/WeakSet and built-ins/Temporal
1 parent de7cf83 commit eeed4fe

6 files changed

Lines changed: 300 additions & 165 deletions

File tree

.github/workflows/test262.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ jobs:
4949
- id: 36
5050
- id: 37
5151
- id: 38
52+
- id: 39
53+
- id: 40
5254
runs-on: ubuntu-latest
5355
steps:
5456
- name: Checkout
@@ -234,6 +236,14 @@ jobs:
234236
TITLE='"built-ins/Symbol" - "built-ins/TypedArrayConstructors"'
235237
FOCUS='built-ins/Symbol,built-ins/ThrowTypeError,built-ins/TypedArrayConstructors'
236238
;;
239+
39)
240+
TITLE='"built-ins/Uint8Array" - "built-ins/WeakSet"'
241+
FOCUS='built-ins/Uint8Array,built-ins/undefined,built-ins/WeakMap,built-ins/WeakRef,built-ins/WeakSet'
242+
;;
243+
40)
244+
TITLE='"built-ins/Temporal"'
245+
FOCUS='built-ins/Temporal'
246+
;;
237247
*)
238248
echo "Unknown subset id: ${{ matrix.id }}" >&2
239249
exit 1

src/core/eval.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12741,44 +12741,54 @@ pub fn evaluate_call_dispatch<'gc>(
1274112741
if let Some(wm_val) = slot_get_chained(obj, &InternalSlot::WeakMap) {
1274212742
if let Value::WeakMap(wm_ptr) = &*wm_val.borrow() {
1274312743
Ok(crate::js_weakmap::handle_weakmap_instance_method(
12744-
mc, wm_ptr, method, eval_args, env,
12744+
mc, wm_ptr, method, eval_args, env, this_v,
1274512745
)?)
1274612746
} else {
12747-
Err(raise_eval_error!("TypeError: WeakMap.prototype method called on incompatible receiver").into())
12747+
Err(
12748+
raise_type_error!(format!("Method WeakMap.prototype.{} called on incompatible receiver", method))
12749+
.into(),
12750+
)
1274812751
}
1274912752
} else {
12750-
Err(raise_eval_error!("TypeError: WeakMap.prototype method called on incompatible receiver").into())
12753+
Err(raise_type_error!(format!("Method WeakMap.prototype.{} called on incompatible receiver", method)).into())
1275112754
}
1275212755
} else if let Value::WeakMap(wm_ptr) = this_v {
1275312756
Ok(crate::js_weakmap::handle_weakmap_instance_method(
12754-
mc, wm_ptr, method, eval_args, env,
12757+
mc, wm_ptr, method, eval_args, env, this_v,
1275512758
)?)
1275612759
} else {
12757-
Err(raise_eval_error!("TypeError: WeakMap.prototype method called on non-object receiver").into())
12760+
Err(raise_type_error!(format!("Method WeakMap.prototype.{} called on incompatible receiver", method)).into())
1275812761
}
1275912762
} else {
12760-
Err(raise_eval_error!(format!("Unknown Map function: {}", name)).into())
12763+
Err(raise_type_error!(format!("Unknown WeakMap function: {}", name)).into())
1276112764
}
1276212765
} else if name.starts_with("WeakSet.") {
1276312766
if let Some(method) = name.strip_prefix("WeakSet.prototype.") {
1276412767
let this_v = this_val.unwrap_or(&Value::Undefined);
1276512768
if let Value::Object(obj) = this_v {
1276612769
if let Some(ws_val) = slot_get_chained(obj, &InternalSlot::WeakSet) {
1276712770
if let Value::WeakSet(ws_ptr) = &*ws_val.borrow() {
12768-
Ok(crate::js_weakset::handle_weakset_instance_method(mc, ws_ptr, method, eval_args)?)
12771+
Ok(crate::js_weakset::handle_weakset_instance_method(
12772+
mc, ws_ptr, method, eval_args, this_v,
12773+
)?)
1276912774
} else {
12770-
Err(raise_eval_error!("TypeError: WeakSet.prototype method called on incompatible receiver").into())
12775+
Err(
12776+
raise_type_error!(format!("Method WeakSet.prototype.{} called on incompatible receiver", method))
12777+
.into(),
12778+
)
1277112779
}
1277212780
} else {
12773-
Err(raise_eval_error!("TypeError: WeakSet.prototype method called on incompatible receiver").into())
12781+
Err(raise_type_error!(format!("Method WeakSet.prototype.{} called on incompatible receiver", method)).into())
1277412782
}
1277512783
} else if let Value::WeakSet(ws_ptr) = this_v {
12776-
Ok(crate::js_weakset::handle_weakset_instance_method(mc, ws_ptr, method, eval_args)?)
12784+
Ok(crate::js_weakset::handle_weakset_instance_method(
12785+
mc, ws_ptr, method, eval_args, this_v,
12786+
)?)
1277712787
} else {
12778-
Err(raise_eval_error!("TypeError: WeakSet.prototype method called on non-object receiver").into())
12788+
Err(raise_type_error!(format!("Method WeakSet.prototype.{} called on incompatible receiver", method)).into())
1277912789
}
1278012790
} else {
12781-
Err(raise_eval_error!(format!("Unknown Map function: {}", name)).into())
12791+
Err(raise_type_error!(format!("Unknown WeakSet function: {}", name)).into())
1278212792
}
1278312793
} else if name == "Set[Symbol.species]" {
1278412794
let this_v = this_val.unwrap_or(&Value::Undefined);
@@ -16450,6 +16460,12 @@ fn evaluate_expr_property<'gc>(
1645016460
| "Set.prototype.has"
1645116461
| "Set.prototype.delete"
1645216462
| "Set.prototype.forEach"
16463+
| "WeakMap.prototype.get"
16464+
| "WeakMap.prototype.has"
16465+
| "WeakMap.prototype.delete"
16466+
| "WeakSet.prototype.add"
16467+
| "WeakSet.prototype.has"
16468+
| "WeakSet.prototype.delete"
1645316469
| "Number.isNaN"
1645416470
| "Number.isFinite"
1645516471
| "Number.isInteger"
@@ -16541,6 +16557,7 @@ fn evaluate_expr_property<'gc>(
1654116557
| "DataView.prototype.setBigInt64"
1654216558
| "DataView.prototype.setBigUint64"
1654316559
| "Map.prototype.set"
16560+
| "WeakMap.prototype.set"
1654416561
| "Math.atan2"
1654516562
| "Math.hypot"
1654616563
| "Math.imul"
@@ -17895,6 +17912,12 @@ fn evaluate_expr_index<'gc>(
1789517912
| "Set.prototype.has"
1789617913
| "Set.prototype.delete"
1789717914
| "Set.prototype.forEach"
17915+
| "WeakMap.prototype.get"
17916+
| "WeakMap.prototype.has"
17917+
| "WeakMap.prototype.delete"
17918+
| "WeakSet.prototype.add"
17919+
| "WeakSet.prototype.has"
17920+
| "WeakSet.prototype.delete"
1789817921
| "Number.isNaN"
1789917922
| "Number.isFinite"
1790017923
| "Number.isInteger"
@@ -17987,6 +18010,7 @@ fn evaluate_expr_index<'gc>(
1798718010
| "DataView.prototype.setBigUint64"
1798818011
| "JSON.parse"
1798918012
| "Map.prototype.set"
18013+
| "WeakMap.prototype.set"
1799018014
| "Math.atan2"
1799118015
| "Math.hypot"
1799218016
| "Math.imul"
@@ -22132,9 +22156,9 @@ fn evaluate_expr_new<'gc>(
2213222156
} else if name_str == "Proxy" {
2213322157
return crate::js_proxy::handle_proxy_constructor(mc, &eval_args, env);
2213422158
} else if name_str == "WeakMap" {
22135-
return Ok(crate::js_weakmap::handle_weakmap_constructor(mc, &eval_args, env)?);
22159+
return crate::js_weakmap::handle_weakmap_constructor(mc, &eval_args, env, None);
2213622160
} else if name_str == "WeakSet" {
22137-
return Ok(crate::js_weakset::handle_weakset_constructor(mc, &eval_args, env)?);
22161+
return crate::js_weakset::handle_weakset_constructor(mc, &eval_args, env, None);
2213822162
} else if name_str == "Set" {
2213922163
return crate::js_set::handle_set_constructor(mc, &eval_args, env, None);
2214022164
} else if name_str == "ArrayBuffer" {

src/js_class.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,8 +1597,8 @@ pub(crate) fn evaluate_new<'gc>(
15971597
"Set" => {
15981598
return crate::js_set::handle_set_constructor(mc, evaluated_args, &ctor_realm_env, new_target);
15991599
}
1600-
"WeakMap" => return Ok(crate::js_weakmap::handle_weakmap_constructor(mc, evaluated_args, &ctor_realm_env)?),
1601-
"WeakSet" => return Ok(crate::js_weakset::handle_weakset_constructor(mc, evaluated_args, &ctor_realm_env)?),
1600+
"WeakMap" => return crate::js_weakmap::handle_weakmap_constructor(mc, evaluated_args, &ctor_realm_env, new_target),
1601+
"WeakSet" => return crate::js_weakset::handle_weakset_constructor(mc, evaluated_args, &ctor_realm_env, new_target),
16021602
"ArrayBuffer" => {
16031603
return crate::js_typedarray::handle_arraybuffer_constructor(mc, evaluated_args, &ctor_realm_env, new_target);
16041604
}

src/js_object.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,12 @@ pub fn handle_object_method<'gc>(
17571757
| "Set.prototype.has"
17581758
| "Set.prototype.delete"
17591759
| "Set.prototype.forEach"
1760+
| "WeakMap.prototype.get"
1761+
| "WeakMap.prototype.has"
1762+
| "WeakMap.prototype.delete"
1763+
| "WeakSet.prototype.add"
1764+
| "WeakSet.prototype.has"
1765+
| "WeakSet.prototype.delete"
17601766
| "Number.isNaN"
17611767
| "Number.isFinite"
17621768
| "Number.isInteger"
@@ -1838,6 +1844,7 @@ pub fn handle_object_method<'gc>(
18381844
| "Function.prototype.apply"
18391845
| "JSON.parse"
18401846
| "Map.prototype.set"
1847+
| "WeakMap.prototype.set"
18411848
| "Math.atan2"
18421849
| "Math.hypot"
18431850
| "Math.imul"

0 commit comments

Comments
 (0)