diff --git a/.changeset/fix-structural-proto-equality.md b/.changeset/fix-structural-proto-equality.md new file mode 100644 index 0000000000..eae88bf89a --- /dev/null +++ b/.changeset/fix-structural-proto-equality.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Fix structural equality for request-style values when structural hashes collide. diff --git a/packages/effect/src/internal/core.ts b/packages/effect/src/internal/core.ts index f0a8c43168..ebcfbbc0be 100644 --- a/packages/effect/src/internal/core.ts +++ b/packages/effect/src/internal/core.ts @@ -87,7 +87,7 @@ export const StructuralProto = { const thatKeys = Object.keys(that) if (selfKeys.length !== thatKeys.length) return false for (let i = 0; i < selfKeys.length; i++) { - if (selfKeys[i] !== thatKeys[i] && !Equal.equals(this[selfKeys[i]], that[selfKeys[i]])) { + if (selfKeys[i] !== thatKeys[i] || !Equal.equals(this[selfKeys[i]], that[selfKeys[i]])) { return false } } diff --git a/packages/effect/test/Request.test.ts b/packages/effect/test/Request.test.ts index 548bb61d3e..58c9b177b3 100644 --- a/packages/effect/test/Request.test.ts +++ b/packages/effect/test/Request.test.ts @@ -1,5 +1,5 @@ import { assert, describe, expect, it } from "@effect/vitest" -import { Array, Context, Data, Fiber } from "effect" +import { Array, Context, Data, Equal, Fiber, Hash } from "effect" import * as Cause from "effect/Cause" import * as Effect from "effect/Effect" import * as Exit from "effect/Exit" @@ -133,6 +133,16 @@ const provideEnv = flow( ) describe.sequential("Request", () => { + it("compares StructuralProto values when hashes collide", () => { + class Req extends Request.Class<{ id: string; account: string }, string> {} + + const a = new Req({ id: "id-8", account: "acct-2811" }) + const b = new Req({ id: "id-14", account: "acct-755" }) + + assert.strictEqual(Hash.hash(a), Hash.hash(b)) + assert.strictEqual(Equal.equals(a, b), false) + }) + it.effect( "requests are executed correctly", Effect.fnUntraced(function*() {