Skip to content

Commit 149da84

Browse files
authored
Merge branch 'main' into fix/number-toprecision-subnormal
2 parents 8f489e3 + 2437b67 commit 149da84

File tree

30 files changed

+2133
-1764
lines changed

30 files changed

+2133
-1764
lines changed

core/engine/src/builtins/array/array_iterator.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,7 @@ pub(crate) struct ArrayIterator {
3939
impl IntrinsicObject for ArrayIterator {
4040
fn init(realm: &Realm) {
4141
BuiltInBuilder::with_intrinsic::<Self>(realm)
42-
.prototype(
43-
realm
44-
.intrinsics()
45-
.objects()
46-
.iterator_prototypes()
47-
.iterator(),
48-
)
42+
.prototype(realm.intrinsics().constructors().iterator().prototype())
4943
.static_method(Self::next, js_string!("next"), 0)
5044
.static_property(
5145
JsSymbol::to_string_tag(),

core/engine/src/builtins/array/from_async.rs

Lines changed: 125 additions & 74 deletions
Large diffs are not rendered by default.

core/engine/src/builtins/array/tests.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,3 +962,26 @@ fn array_of_neg_zero() {
962962
TestAction::assert("arr.every(x => (1/x) === -Infinity)"),
963963
]);
964964
}
965+
966+
#[test]
967+
fn array_prototype_find_edge_cases() {
968+
run_test_actions([
969+
TestAction::run_harness(),
970+
TestAction::assert("[].find(x => x === 1) === undefined"),
971+
TestAction::assert("[1, 2, 3].find(x => x === 99) === undefined"),
972+
TestAction::assert("[1, 2, 1].find(x => x === 1) === 1"),
973+
TestAction::assert(indoc! {r#"
974+
var obj = { name: "Alice" };
975+
[obj].find(x => x.name === "Alice") === obj
976+
"#}),
977+
TestAction::assert(indoc! {r#"
978+
var idx = -1;
979+
[10, 20, 30].find((v, i) => { idx = i; return v === 20; });
980+
idx === 1
981+
"#}),
982+
TestAction::assert(indoc! {r#"
983+
let arr = [1, , 3];
984+
arr.find(x => x === undefined) === undefined
985+
"#}),
986+
]);
987+
}

core/engine/src/builtins/builder.rs

Lines changed: 42 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,6 @@ pub(crate) struct BuiltInConstructorWithPrototype<'ctx> {
178178
__proto__: JsPrototype,
179179
inherits: Option<JsObject>,
180180
attributes: Attribute,
181-
/// If `Some`, the `constructor` property on the prototype will be installed
182-
/// as a get/set accessor pair instead of as a writable data property.
183-
/// This is needed by `Iterator.prototype.constructor` per the spec
184-
/// (web-compat requirement).
185-
constructor_accessor: Option<(JsFunction, JsFunction)>,
186181
}
187182

188183
#[allow(dead_code)]
@@ -199,13 +194,6 @@ impl BuiltInConstructorWithPrototype<'_> {
199194
/// See [`BuiltInConstructorWithPrototype::build`].
200195
const OWN_PROTOTYPE_STORAGE_SLOTS: usize = 1;
201196

202-
/// The number of storage slots properties that are always present in a
203-
/// standard constructor's prototype object when `constructor` is installed
204-
/// as a get/set **accessor** property (two slots: getter + setter).
205-
///
206-
/// See [`BuiltInConstructorWithPrototype::constructor_accessor`].
207-
const OWN_PROTOTYPE_STORAGE_SLOTS_ACCESSOR: usize = 2;
208-
209197
/// Specify how many arguments the constructor function takes.
210198
///
211199
/// Default is `0`.
@@ -390,25 +378,6 @@ impl BuiltInConstructorWithPrototype<'_> {
390378
self
391379
}
392380

393-
/// Installs `Iterator.prototype.constructor` (or any analogous property) as a
394-
/// configurable, non-enumerable **accessor** descriptor instead of the default
395-
/// writable data property.
396-
///
397-
/// Per the [ECMAScript spec][spec], `Iterator.prototype.constructor` must be an
398-
/// accessor for web-compatibility reasons: previously the property did not exist, so
399-
/// making it a setter that ignores writes to the prototype avoids breaking existing code
400-
/// that assigns `Iterator.prototype.constructor = ...`.
401-
///
402-
/// When this method is called the `PROTOTYPE_STORAGE_SLOTS` constant on the
403-
/// implementing built-in **must** account for two extra slots (getter + setter)
404-
/// instead of the usual one slot for a data property.
405-
///
406-
/// [spec]: https://tc39.es/ecma262/#sec-iterator.prototype.constructor
407-
pub(crate) fn constructor_accessor(mut self, get: JsFunction, set: JsFunction) -> Self {
408-
self.constructor_accessor = Some((get, set));
409-
self
410-
}
411-
412381
#[track_caller]
413382
pub(crate) fn build(mut self) {
414383
let length = self.length;
@@ -418,52 +387,19 @@ impl BuiltInConstructorWithPrototype<'_> {
418387
self = self.static_property(js_string!("name"), name, Attribute::CONFIGURABLE);
419388
self = self.static_property(PROTOTYPE, prototype, Attribute::empty());
420389

421-
// Install the `constructor` property on the prototype — either as a writable
422-
// data property (the common case) or as a get/set accessor (needed by
423-
// `Iterator.prototype.constructor` for web-compat, see `constructor_accessor`).
424-
if let Some((get, set)) = self.constructor_accessor.take() {
425-
// Accessor path: two storage slots (getter + setter). The `CONSTRUCTOR` key
426-
// must NOT already be present (no duplicate insertion).
427-
let mut attributes = SlotAttributes::CONFIGURABLE;
428-
attributes.set(SlotAttributes::GET, true);
429-
attributes.set(SlotAttributes::SET, true);
430-
debug_assert!(
431-
!self
432-
.prototype_property_table
433-
.map
434-
.contains_key(&CONSTRUCTOR.into())
435-
);
436-
self.prototype_property_table
437-
.insert(CONSTRUCTOR.into(), attributes);
438-
self.prototype_storage
439-
.extend([JsValue::new(get), JsValue::new(set)]);
440-
#[cfg(debug_assertions)]
441-
assert!(
442-
self.prototype_storage.len()
443-
<= self.prototype_storage_slots_expected
444-
+ Self::OWN_PROTOTYPE_STORAGE_SLOTS_ACCESSOR,
445-
"expected to allocate at most {} prototype storage slots, got {}. \
446-
constant {}::PROTOTYPE_STORAGE_SLOTS may need to be adjusted",
447-
self.prototype_storage_slots_expected,
448-
self.prototype_storage.len() - Self::OWN_PROTOTYPE_STORAGE_SLOTS_ACCESSOR,
449-
self.name.display_escaped(),
450-
);
451-
} else {
452-
// Data property path (the default).
453-
let attributes = self.attributes;
454-
let object = self.constructor.clone();
455-
self = self.property(CONSTRUCTOR, object, attributes);
456-
#[cfg(debug_assertions)]
457-
assert!(
458-
self.prototype_storage.len()
459-
<= self.prototype_storage_slots_expected + Self::OWN_PROTOTYPE_STORAGE_SLOTS,
460-
"expected to allocate at most {} prototype storage slots, got {}. \
390+
let attributes = self.attributes;
391+
let object = self.constructor.clone();
392+
self = self.property(CONSTRUCTOR, object, attributes);
393+
#[cfg(debug_assertions)]
394+
assert!(
395+
self.prototype_storage.len()
396+
<= self.prototype_storage_slots_expected + Self::OWN_PROTOTYPE_STORAGE_SLOTS,
397+
"expected to allocate at most {} prototype storage slots, got {}. \
461398
constant {}::PROTOTYPE_STORAGE_SLOTS may need to be adjusted",
462-
self.prototype_storage_slots_expected,
463-
self.prototype_storage.len() - Self::OWN_PROTOTYPE_STORAGE_SLOTS,
464-
self.name.display_escaped(),
465-
);
466-
}
399+
self.prototype_storage_slots_expected,
400+
self.prototype_storage.len() - Self::OWN_PROTOTYPE_STORAGE_SLOTS,
401+
self.name.display_escaped(),
402+
);
467403

468404
#[cfg(debug_assertions)]
469405
assert!(
@@ -682,7 +618,6 @@ impl<'ctx> BuiltInBuilder<'ctx, Callable<Constructor>> {
682618
__proto__: Some(realm.intrinsics().constructors().function().prototype()),
683619
inherits: Some(realm.intrinsics().constructors().object().prototype()),
684620
attributes: Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE,
685-
constructor_accessor: None,
686621
}
687622
}
688623
}
@@ -730,6 +665,36 @@ impl<T> BuiltInBuilder<'_, T> {
730665
self
731666
}
732667

668+
/// Adds a new accessor property to the builtin object.
669+
pub(crate) fn static_accessor<K>(
670+
self,
671+
key: K,
672+
get: Option<JsFunction>,
673+
set: Option<JsFunction>,
674+
attribute: Attribute,
675+
) -> Self
676+
where
677+
K: Into<PropertyKey>,
678+
{
679+
let mut property = PropertyDescriptor::builder()
680+
.enumerable(attribute.enumerable())
681+
.configurable(attribute.configurable());
682+
683+
if let Some(get) = get {
684+
property = property.get(get);
685+
}
686+
687+
if let Some(set) = set {
688+
property = property.set(set);
689+
}
690+
691+
let key = key.into();
692+
693+
self.object.insert(key, property);
694+
695+
self
696+
}
697+
733698
/// Specify the `[[Prototype]]` internal field of the builtin object.
734699
///
735700
/// Default is `Function.prototype` for constructors and `Object.prototype` for statics.

core/engine/src/builtins/generator/mod.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,7 @@ pub struct Generator {
156156
impl IntrinsicObject for Generator {
157157
fn init(realm: &Realm) {
158158
BuiltInBuilder::with_intrinsic::<Self>(realm)
159-
.prototype(
160-
realm
161-
.intrinsics()
162-
.objects()
163-
.iterator_prototypes()
164-
.iterator(),
165-
)
159+
.prototype(realm.intrinsics().constructors().iterator().prototype())
166160
.static_method(Self::next, js_string!("next"), 1)
167161
.static_method(Self::r#return, js_string!("return"), 1)
168162
.static_method(Self::throw, js_string!("throw"), 1)

0 commit comments

Comments
 (0)