Skip to content

Runtime builtins use untyped errors, breaking typed .catch() dispatch #46

@brianp

Description

@brianp

Problem

Runtime builtin functions that throw errors use aster_error_set() (untyped) instead of aster_error_set_typed(class_tag, value). This means .catch(SpecificError e) arms never match because aster_error_get_tag() returns 0, which doesn't correspond to any class ID.

The typechecker correctly declares these functions as throws SpecificError, so the type system thinks typed catching should work, but at runtime the tag is missing and the catch arm falls through to the wildcard or re-raises.

Root cause

FIR class IDs are assigned dynamically during lowering. Runtime functions are compiled Rust code that doesn't know these IDs. There's no mechanism to pass the class tag from the FIR layer to the runtime function.

Affected builtins

  • File.read() - declares throws IOError, uses aster_error_set() in codegen/src/runtime/fs.rs
  • File.write() - declares throws IOError, uses aster_error_set() in codegen/src/runtime/fs.rs
  • File.append() - declares throws IOError, uses aster_error_set() in codegen/src/runtime/fs.rs
  • process.run() - declares throws ProcessError, uses aster_error_set() in codegen/src/runtime/process.rs
  • Int.from() (new, Add to_int() stdlib function for string-to-integer conversion #44) - declares throws IntParseError, will use aster_error_set()

Possible solutions

  1. Pre-register builtin error classes with sentinel ClassIds in Lowerer::new() (like FieldInfo uses u32::MAX) and hardcode those sentinels in the runtime functions. Simple but couples magic constants across layers.

  2. Emit error-set inline in FIR: Runtime functions signal failure via a return convention, and FIR lowering emits aster_error_set_typed(tag, 0) at the call site where the class tag is known.

  3. Pass the class tag as an argument to each throwing runtime function so it can call aster_error_set_typed(tag, value) itself. The FIR lowering supplies the tag at each call site.

Impact

Users who write .catch(IOError e) or .catch(IntParseError e) on runtime builtins will silently fail to match. Only wildcard catches (!.catch { ... }) and !.or(default) work correctly today.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions