-
Notifications
You must be signed in to change notification settings - Fork 621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(assert): check property equality up the prototype chain (#6151) #6153
Conversation
|
||
function compare(a: unknown, b: unknown): boolean { | ||
if (sameValueZero(a, b)) return true; | ||
if (isPrimitive(a) || isPrimitive(b)) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Front-loaded cheaper checks in an effort to make sure perf wasn't adversely affected for most cases (earlier versions seemed to have significant adverse impact on perf).
return a.constructor === b.constructor || | ||
a.constructor === Object && !b.constructor || | ||
!a.constructor && b.constructor === Object; | ||
function prototypesEqual(a: object, b: object) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed constructorsEqual
to prototypesEqual
because obj.constructor
can easily be faked or inadvertently changed, whereas Object.getPrototypeOf
can't (without monkey-patching Object.getPrototypeOf
itself). This was necessitated due to some of the other changes affecting tests such as assertFalse(equal(new WeakMap(), { constructor: WeakMap }));
pa === null && pb === Object.prototype; | ||
} | ||
|
||
function isBasicObjectOrArray(obj: object) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When an object has null prototype or is a plain object/array, we don't care about checking other properties in its prototype chain.
proto === Array.prototype; | ||
} | ||
|
||
// Slightly faster than Reflect.ownKeys in V8 as of 12.9.202.13-rusty (2024-10-28) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this is the case 🤷
|
||
type TypedArray = Pick<Uint8Array | BigUint64Array, "length" | number>; | ||
const TypedArray = Object.getPrototypeOf(Uint8Array); | ||
function compareTypedArrays(a: TypedArray, b: TypedArray) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Necessitated its own path due to equals() works with .subarray()
test of bytes/equals_test.ts
(otherwise the equality will fail due to checking byteOffset
on the prototype).
* @param c The actual value | ||
* @param d The expected value | ||
* @param a The actual value | ||
* @param b The expected value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope it's OK to rename these, it seemed confusing that the variables a
and b
were named c
and d
in the public function.
if (a instanceof TypedArray) { | ||
return compareTypedArrays(a as TypedArray, b as TypedArray); | ||
} | ||
if (a instanceof WeakMap) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only necessary to check a
for these checks now because prototypes are equal (rather than just any property that happens to be named "constructor").
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #6153 +/- ##
=======================================
Coverage 96.53% 96.53%
=======================================
Files 538 538
Lines 40902 40942 +40
Branches 6150 6150
=======================================
+ Hits 39483 39522 +39
- Misses 1375 1376 +1
Partials 44 44 ☔ View full report in Codecov by Sentry. |
This sounds fine to me as correctness matters more here.
These are impressive improvements! Thanks for these works! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Fixes #6151.
Fixes #6165.
Benchmarks below.
Benchmark summary:
Temporal.PlainDate
,Intl.Locale
,URL
, andURLPattern
are all significantly slower (but within an order of magnitude), which I'd say is an acceptable tradeoff for now consistently giving correct results.URLSearchParams
is significantly faster (also within an order of magnitude) in addition to the consistently correct results.Uint8Array
is much faster (I only added a fast path for typed arrays to fix tests withsubarray
failing due to now walking the prototype chain).