Found during a full documentation-validation sweep of the compiler (Aug 2026). Each item below is individually fine; the pattern is the concern — the typechecker is becoming the place where every feature lands as an inline special case, which makes it progressively harder to modify safely.
Symptoms
typecheck/src/check_call.rs (1,796 lines) intercepts special forms by name, inline:
is_a — check_call.rs:88
responds_to — check_call.rs:91
contains predicate overload — check_call.rs:174
Set[T]() constructor parsed as Call(Index(...)) — check_call.rs:235
resolve_all / resolve_first — check_call.rs:295-296 (plus their function types re-declared at check_call.rs:1318-1330)
Mutex, Channel, MultiSend, MultiReceive constructors — check_call.rs:297-298
- plus
List[Nil] push-promotion and the DynamicReceiver method/bare-call fallback
typecheck/src/typechecker.rs (2,742 lines) carries accreted per-feature state flags:
is_main — typechecker.rs:30
const_names — typechecker.rs:35
task_bindings — typechecker.rs:40
boundary_crossed — typechecker.rs:47
nil_promotions — typechecker.rs:68
The standard library exists only as Rust tables inside the typechecker (register_builtins(), builtin_std_submodule_exports()) plus runtime intrinsics — there is no Aster-source stdlib layer. This also cuts against the stated goal that the stdlib not just be wrappers over host code.
Possible directions
- A registry/mechanism for builtin constructors and intercepted calls instead of string matches inside
check_call, so adding a builtin doesn't mean editing the dispatch spine.
- Audit the per-feature state fields for consolidation into scoped context objects (some already moved to
ScopeContext).
- Longer-term: an Aster-source stdlib layer that typechecks like user code and lowers to the same intrinsics, so the Rust tables shrink to true primitives.
Documentation
Current behavior is documented (code-verified) in the docs site: docs/src/content/docs/internals/type-checker.mdx and internals/virtual-stdlib.mdx.
Found during a full documentation-validation sweep of the compiler (Aug 2026). Each item below is individually fine; the pattern is the concern — the typechecker is becoming the place where every feature lands as an inline special case, which makes it progressively harder to modify safely.
Symptoms
typecheck/src/check_call.rs(1,796 lines) intercepts special forms by name, inline:is_a—check_call.rs:88responds_to—check_call.rs:91containspredicate overload —check_call.rs:174Set[T]()constructor parsed asCall(Index(...))—check_call.rs:235resolve_all/resolve_first—check_call.rs:295-296(plus their function types re-declared atcheck_call.rs:1318-1330)Mutex,Channel,MultiSend,MultiReceiveconstructors —check_call.rs:297-298List[Nil]push-promotion and the DynamicReceiver method/bare-call fallbacktypecheck/src/typechecker.rs(2,742 lines) carries accreted per-feature state flags:is_main—typechecker.rs:30const_names—typechecker.rs:35task_bindings—typechecker.rs:40boundary_crossed—typechecker.rs:47nil_promotions—typechecker.rs:68The standard library exists only as Rust tables inside the typechecker (
register_builtins(),builtin_std_submodule_exports()) plus runtime intrinsics — there is no Aster-source stdlib layer. This also cuts against the stated goal that the stdlib not just be wrappers over host code.Possible directions
check_call, so adding a builtin doesn't mean editing the dispatch spine.ScopeContext).Documentation
Current behavior is documented (code-verified) in the docs site:
docs/src/content/docs/internals/type-checker.mdxandinternals/virtual-stdlib.mdx.