Skip to content

RFC: THR003 — under-declared throws from callback parameter throws annotations #73

@marcelofarias

Description

@marcelofarias

Motivation

EFF003/EFF004 (PR #72) enforce that a higher-order fn's capability surface must cover the uses {}, reads {}, and writes {} annotations on its callback parameters. The same principle applies to throws {}: if a callback parameter declares throws { NetworkError }, the outer fn can exercise that throw through any call to the callback — so the outer fn's own throws {} must cover it.

Currently there is no check for this. Example:

```bs
?bs 0.9

fn process(
items: string[],
handler: fn(string) throws { NetworkError } -> void
) -> void { // ← should fire THR003: missing throws { NetworkError }
handler(items[0])
}
```

If the outer fn calls handler(...), it can surface NetworkError. A reviewer reading the outer fn's header sees no throws declaration and has no warning that calling it may produce a network error.

Proposed Diagnostic

THR003: fires when a function-typed parameter carries throws { X } but the containing fn does not declare throws { X } in its own header.

This is the direct analogue of EFF003 (reads on callback) and EFF004 (writes on callback), applied to the throws surface.

Implementation Sketch

Extend thr-check.ts (or a new pass) to:

  1. Walk each fn declaration's parameter list for function-typed parameters.
  2. For each such parameter, collect throws {} labels (same pattern as paramReads/paramWrites in parse-fn.ts for EFF003/EFF004).
  3. Union those labels into the fn's required-throws set.
  4. Emit THR003 if any required label is absent from the fn's own throws {} declaration.

Gate: ?bs 0.9 (same as THR001/THR002).

Prior Art in This Codebase

Notes

  • Strip throws {} from callback parameter types in emitted TypeScript (same as reads {}/writes {} stripping in buildArgsTs).
  • The rule is "the fn's throws surface is the union of its own declared throws AND the throws its callback parameters may exercise."
  • Closes the "callback throws-leak" vector — a higher-order fn cannot advertise a narrower throws surface than it can actually exercise.

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionDesign discussion or RFCenhancementNew feature or requestproposalRFC or design proposal

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions