Skip to content

Commit

Permalink
Allow Exit subtype to be a floating Effect
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiamanzati committed Mar 3, 2025
1 parent 796db99 commit 59af0f4
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/metal-buses-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/language-service": patch
---

Allow Exit subtype to be a floating Effect
5 changes: 5 additions & 0 deletions examples/diagnostics/floatingEffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@ Effect.runPromise(Effect.gen(function*(){

export function constructorFunction(this: { boot: Effect.Effect<void>}){
this.boot = Effect.void
// ^- This is fine, its another way to perform an assignment
}

const main = Effect.gen(function*(){
yield* Effect.exit(Effect.void)
// ^- This is fine, returns an exit
})
8 changes: 6 additions & 2 deletions src/diagnostics/floatingEffect.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { pipe } from "effect/Function"
import * as Option from "effect/Option"
import ts from "typescript"
import type { ApplicableDiagnosticDefinition } from "../definition.js"
Expand Down Expand Up @@ -31,8 +32,11 @@ export const floatingEffect = createDiagnostic({
const effect = TypeParser.effectType(ts, typeChecker)(type, node.expression)
if (Option.isSome(effect)) {
// and not a fiber (we consider that a valid operation)
const fiber = TypeParser.fiberType(ts, typeChecker)(type, node.expression)
if (Option.isNone(fiber)) {
const allowedFloatingEffects = pipe(
TypeParser.fiberType(ts, typeChecker)(type, node.expression),
Option.orElse(() => TypeParser.effectSubtype(ts, typeChecker)(type, node.expression))
)
if (Option.isNone(allowedFloatingEffects)) {
effectDiagnostics.push({
node,
category: ts.DiagnosticCategory.Error,
Expand Down
15 changes: 15 additions & 0 deletions src/utils/TypeParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,21 @@ export function fiberType(ts: TypeScriptApi, typeChecker: ts.TypeChecker) {
})
}

export function effectSubtype(ts: TypeScriptApi, typeChecker: ts.TypeChecker) {
return (type: ts.Type, atLocation: ts.Node) =>
Option.gen(function*(_) {
// there is no better way to check if a type is a subtype of effect
// so we just check for the existence of the property "_tag"
// which is common for Option, Either, and others
const tagSymbol = yield* Option.fromNullable(
typeChecker.getPropertyOfType(type, "_tag")
)
if (!tagSymbol) return yield* Option.none()
// and it is also an effect itself
return effectType(ts, typeChecker)(type, atLocation)
})
}

export function importedEffectModule(ts: TypeScriptApi, typeChecker: ts.TypeChecker) {
return (node: ts.Node) =>
Option.gen(function*() {
Expand Down

0 comments on commit 59af0f4

Please sign in to comment.