Skip to content

RFC: THR002 — under-declared throws from direct error construction #65

@marcelofarias

Description

@marcelofarias

The gap

THR001 enforces that callers propagate `throws {}` transitively up the call graph. But there is no check on the source side: a leaf fn declaring `throws { X }` without any evidence that its body actually produces `X` is silently accepted. More importantly, the dangerous case is the inverse:

```bs
fn parseConfig(s: string) -> Result<Config, ParseError> {
if (bad) err(NetworkError("timed out")) // NetworkError not declared!
else ok(config)
}
```

The fn returns `Result<Config, ParseError>` but the body constructs `Err(NetworkError(...))`. Callers that match on `ParseError` will never see a `NetworkError` arm — and THR001 won't fire because `parseConfig` doesn't declare `throws { NetworkError }`.

Proposal

```
THR002 fn body constructs err(TypeName(...)) or err(TypeName) where TypeName
is not present in the fn's throws {} set.
```

Mechanically: scan the fn body for `err(` patterns where the first argument is an ident that looks like a constructor (CapCase, followed by `(` or `)`). If that ident is not in the fn's own `throws {}` set (or the transitively declared throws of the fn's callees), fire THR002.

Over-declaration (`throws { X }` declared but X never produced) remains allowed — same policy as THR001 and DEP001/DEP002.

Scope

Token-based detection is reliable for direct construction patterns:

  • `err(HttpError(msg))` → detects `HttpError`
  • `err(new ParseError(...))` → detects `ParseError`

Indirect patterns (`err(e)` where `e` has a type) require inference and are out of scope.

Relationship to existing diagnostics

Version gate

`?bs 0.9` alongside THR001 — same generation of checks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionDesign discussion or RFCenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions