diff --git a/.changeset/wicked-bears-flow.md b/.changeset/wicked-bears-flow.md
new file mode 100644
index 00000000000..1781cd7b07e
--- /dev/null
+++ b/.changeset/wicked-bears-flow.md
@@ -0,0 +1,6 @@
+---
+"effect": minor
+---
+
+`Resource` is subtype of `Effect`.
+`ScopedRed` is subtype of `Effect`.
diff --git a/packages/effect/dtslint/Unify.ts b/packages/effect/dtslint/Unify.ts
index 8a122c7e871..926da4eb361 100644
--- a/packages/effect/dtslint/Unify.ts
+++ b/packages/effect/dtslint/Unify.ts
@@ -9,6 +9,8 @@ import type * as Option from "effect/Option"
import type * as Queue from "effect/Queue"
import type * as RcRef from "effect/RcRef"
import type * as Ref from "effect/Ref"
+import type * as Resource from "effect/Resource"
+import type * as ScopedRef from "effect/ScopedRef"
import type * as Stream from "effect/Stream"
import type * as SubscriptionRef from "effect/SubscriptionRef"
import type * as SynchronizedRef from "effect/SynchronizedRef"
@@ -109,8 +111,21 @@ export type DequeueUnify = Unify.Unify<
| Queue.Dequeue<1>
| Queue.Dequeue<"a">
>
+// $ExpectType ScopedRef<1> | ScopedRef<"a">
+export type ScopedRefUnify = Unify.Unify<
+ | ScopedRef.ScopedRef<1>
+ | ScopedRef.ScopedRef<"a">
+>
+// $ExpectType Resource<1, never> | Resource | Resource<1, 2> | Resource<"a", "b"> | Resource
+export type ResourceUnify = Unify.Unify<
+ | Resource.Resource<1>
+ | Resource.Resource
+ | Resource.Resource<1, 2>
+ | Resource.Resource<"a", "b">
+ | Resource.Resource
+>
-// $ExpectType 0 | Option | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Deferred<1, 2> | Deferred<"a", "b"> | Fiber<"a" | 1, "b" | 2> | RuntimeFiber<"a" | 1, "b" | 2> | Queue<1> | Queue<"a"> | Dequeue<"a" | 1> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | FiberRef<12> | FiberRef<"a2"> | Either<1 | "A", 0 | "E"> | Effect<1 | "A", 0 | "E", "R" | "R1"> | RcRef<1 | "A", 0 | "E">
+// $ExpectType 0 | Option | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Deferred<1, 2> | Deferred<"a", "b"> | Fiber<"a" | 1, "b" | 2> | RuntimeFiber<"a" | 1, "b" | 2> | Queue<1> | Queue<"a"> | Dequeue<"a" | 1> | ScopedRef<1> | ScopedRef<"a"> | Resource<1, 2> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | FiberRef<12> | FiberRef<"a2"> | Resource<"a", never> | Either<1 | "A", 0 | "E"> | Effect<1 | "A", 0 | "E", "R" | "R1"> | RcRef<1 | "A", 0 | "E">
export type AllUnify = Unify.Unify<
| Either.Either<1, 0>
| Either.Either<"A", "E">
@@ -138,5 +153,9 @@ export type AllUnify = Unify.Unify<
| Queue.Queue<"a">
| Queue.Dequeue<1>
| Queue.Dequeue<"a">
+ | ScopedRef.ScopedRef<1>
+ | ScopedRef.ScopedRef<"a">
+ | Resource.Resource<1, 2>
+ | Resource.Resource<"a">
| 0
>
diff --git a/packages/effect/src/Resource.ts b/packages/effect/src/Resource.ts
index dc9af2a864b..8dc6debd349 100644
--- a/packages/effect/src/Resource.ts
+++ b/packages/effect/src/Resource.ts
@@ -4,10 +4,12 @@
import type * as Effect from "./Effect.js"
import type * as Exit from "./Exit.js"
import * as internal from "./internal/resource.js"
+import type { Pipeable } from "./Pipeable.js"
import type * as Schedule from "./Schedule.js"
import type * as Scope from "./Scope.js"
import type * as ScopedRef from "./ScopedRef.js"
import type * as Types from "./Types.js"
+import type * as Unify from "./Unify.js"
/**
* @since 2.0.0
@@ -28,11 +30,31 @@ export type ResourceTypeId = typeof ResourceTypeId
* @since 2.0.0
* @category models
*/
-export interface Resource extends Resource.Variance {
+export interface Resource extends Effect.Effect, Resource.Variance, Pipeable {
/** @internal */
readonly scopedRef: ScopedRef.ScopedRef>
/** @internal */
readonly acquire: Effect.Effect
+
+ readonly [Unify.typeSymbol]?: unknown
+ readonly [Unify.unifySymbol]?: ResourceUnify
+ readonly [Unify.ignoreSymbol]?: ResourceUnifyIgnore
+}
+
+/**
+ * @category models
+ * @since 3.9.0
+ */
+export interface ResourceUnify extends Effect.EffectUnify {
+ Resource?: () => Extract>
+}
+
+/**
+ * @category models
+ * @since 3.9.0
+ */
+export interface ResourceUnifyIgnore extends Effect.EffectUnifyIgnore {
+ Effect?: true
}
/**
diff --git a/packages/effect/src/ScopedRef.ts b/packages/effect/src/ScopedRef.ts
index cc46efb205d..8d44654afbf 100644
--- a/packages/effect/src/ScopedRef.ts
+++ b/packages/effect/src/ScopedRef.ts
@@ -8,6 +8,7 @@ import type { Pipeable } from "./Pipeable.js"
import type * as Scope from "./Scope.js"
import type * as Synchronized from "./SynchronizedRef.js"
import type * as Types from "./Types.js"
+import type * as Unify from "./Unify.js"
/**
* @since 2.0.0
@@ -31,9 +32,29 @@ export type ScopedRefTypeId = typeof ScopedRefTypeId
* @since 2.0.0
* @category models
*/
-export interface ScopedRef extends ScopedRef.Variance, Pipeable {
+export interface ScopedRef extends Effect.Effect, ScopedRef.Variance, Pipeable {
/** @internal */
readonly ref: Synchronized.SynchronizedRef
+
+ readonly [Unify.typeSymbol]?: unknown
+ readonly [Unify.unifySymbol]?: ScopedRefUnify
+ readonly [Unify.ignoreSymbol]?: ScopedRefUnifyIgnore
+}
+
+/**
+ * @category models
+ * @since 3.9.0
+ */
+export interface ScopedRefUnify extends Effect.EffectUnify {
+ ScopedRef?: () => Extract>
+}
+
+/**
+ * @category models
+ * @since 3.9.0
+ */
+export interface ScopedRefUnifyIgnore extends Effect.EffectUnifyIgnore {
+ Effect?: true
}
/**
diff --git a/packages/effect/src/internal/resource.ts b/packages/effect/src/internal/resource.ts
index 74a21dc314f..bd1bf5e706c 100644
--- a/packages/effect/src/internal/resource.ts
+++ b/packages/effect/src/internal/resource.ts
@@ -4,6 +4,7 @@ import type * as Resource from "../Resource.js"
import type * as Schedule from "../Schedule.js"
import type * as Scope from "../Scope.js"
import * as core from "./core.js"
+import * as effectable from "./effectable.js"
import * as fiberRuntime from "./fiberRuntime.js"
import * as _schedule from "./schedule.js"
import * as scopedRef from "./scopedRef.js"
@@ -23,6 +24,15 @@ const resourceVariance = {
_A: (_: any) => _
}
+/** @internal */
+const proto: ThisType> = {
+ ...effectable.CommitPrototype,
+ commit() {
+ return get(this)
+ },
+ [ResourceTypeId]: resourceVariance
+}
+
/** @internal */
export const auto = (
acquire: Effect.Effect,
@@ -46,11 +56,12 @@ export const manual = (
core.flatMap(core.context(), (env) =>
pipe(
scopedRef.fromAcquire(core.exit(acquire)),
- core.map((ref) => ({
- [ResourceTypeId]: resourceVariance,
- scopedRef: ref,
- acquire: core.provideContext(acquire, env)
- }))
+ core.map((ref) => {
+ const resource = Object.create(proto)
+ resource.scopedRef = ref
+ resource.acquire = core.provideContext(acquire, env)
+ return resource
+ })
))
/** @internal */
diff --git a/packages/effect/src/internal/scopedRef.ts b/packages/effect/src/internal/scopedRef.ts
index 2e588c36b7a..dca8d7d4810 100644
--- a/packages/effect/src/internal/scopedRef.ts
+++ b/packages/effect/src/internal/scopedRef.ts
@@ -2,11 +2,11 @@ import * as Context from "../Context.js"
import type * as Effect from "../Effect.js"
import type { LazyArg } from "../Function.js"
import { dual, pipe } from "../Function.js"
-import { pipeArguments } from "../Pipeable.js"
import type * as Scope from "../Scope.js"
import type * as ScopedRef from "../ScopedRef.js"
import * as core from "./core.js"
import * as circular from "./effect/circular.js"
+import * as effectable from "./effectable.js"
import * as fiberRuntime from "./fiberRuntime.js"
import * as ref from "./ref.js"
import * as synchronized from "./synchronizedRef.js"
@@ -25,6 +25,15 @@ const scopedRefVariance = {
_A: (_: any) => _
}
+/** @internal */
+const proto: ThisType> = {
+ ...effectable.CommitPrototype,
+ commit() {
+ return get(this)
+ },
+ [ScopedRefTypeId]: scopedRefVariance
+}
+
/** @internal */
const close = (self: ScopedRef.ScopedRef): Effect.Effect =>
core.flatMap(ref.get(self.ref), (tuple) => tuple[0].close(core.exitVoid))
@@ -41,13 +50,8 @@ export const fromAcquire = (
core.flatMap((value) =>
circular.makeSynchronized([newScope, value] as const).pipe(
core.flatMap((ref) => {
- const scopedRef: ScopedRef.ScopedRef = {
- [ScopedRefTypeId]: scopedRefVariance,
- pipe() {
- return pipeArguments(this, arguments)
- },
- ref
- }
+ const scopedRef = Object.create(proto)
+ scopedRef.ref = ref
return pipe(
fiberRuntime.addFinalizer(() => close(scopedRef)),
core.as(scopedRef)
diff --git a/packages/effect/test/Resource.test.ts b/packages/effect/test/Resource.test.ts
index 5043b9530ce..a2b7af50f5b 100644
--- a/packages/effect/test/Resource.test.ts
+++ b/packages/effect/test/Resource.test.ts
@@ -51,4 +51,12 @@ describe("Resource", () => {
assert.strictEqual(result1, 0)
assert.strictEqual(result2, 0)
}))
+ it.scoped("subtype of Effect", () =>
+ Effect.gen(function*() {
+ const ref = yield* Ref.make(0)
+ const cached = yield* Cached.manual(ref)
+ const resul1 = yield* cached
+
+ assert.strictEqual(resul1, 0)
+ }))
})
diff --git a/packages/effect/test/ScopedRef.test.ts b/packages/effect/test/ScopedRef.test.ts
index fcd55f6100f..f4c942c9221 100644
--- a/packages/effect/test/ScopedRef.test.ts
+++ b/packages/effect/test/ScopedRef.test.ts
@@ -79,4 +79,10 @@ describe("ScopedRef", () => {
const ref = yield* _(Effect.scoped(ScopedRef.make(() => 0)))
expect(ref.pipe(identity)).toBe(ref)
}))
+ it.scoped("subtype of Effect", () =>
+ Effect.gen(function*() {
+ const ref = yield* ScopedRef.make(() => 0)
+ const result = yield* ref
+ assert.strictEqual(result, 0)
+ }))
})