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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions