Skip to content

Add missing exhaustiveness guards in Layer.buildWithScope and FiberRuntime.evaluateEffect #6158

@savarin

Description

@savarin

Description

Two dispatch points in Effect's internals are missing the absurd exhaustiveness guard that's already used elsewhere in the same codebase. Reproduction of issues [here](Reproduction of all three issues in full here.).

1. Layer.buildWithScope — missing default case

packages/effect/src/internal/layer.ts:494 — the switch on op._op_layer covers all current layer op codes but has no default: absurd(op). If a new layer op is added without updating this switch, it silently falls through with no result.

// Current — no default case
switch (op._op_layer) {
  case "Provide": { ... }
  case "ExtendScope": { ... }
  case "ZipWith": { ... }
  case "MergeAll": { ... }
  // NEW OP ADDED HERE → silently produces no result
}

The same absurd pattern is already used at 5 dispatch points in fiberRuntime.ts (lines 129, 931, 1166, 1182, 1221).

2. FiberRuntime.evaluateEffect — missing else branch

packages/effect/src/internal/fiberRuntime.ts:962-965 — the if/else if chain for OP_SYNC/OP_ASYNC has no final else:

// Current — no else branch
if (op._op === OpCodes.OP_SYNC) {
  // ...
} else if (op._op === OpCodes.OP_YIELD) {
  // ...
} else if (op._op === OpCodes.OP_ASYNC) {
  effect = null
}
// NEW OP ADDED HERE → silently produces no result

absurd is already defined at line 129 of this file and used at 4 other dispatch points in the continuation handler — this evaluation dispatch was missed.

Context

I found these by formalizing Effect's op code dispatch as an inductive type in Lean 4, which makes exhaustiveness trivially provable. The TypeScript dispatch uses string-based op codes where the compiler doesn't enforce exhaustiveness — the absurd pattern is Effect's solution to this, but two spots were missed. The invariant analysis methodology is documented at github.com/savarin/lean-agent.

I have a working implementation (9 lines, 2 files) and would be happy to open a PR. Type-checks clean against packages/effect/tsconfig.src.json.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions