a665e2c1a5
This commit refactors the call hook mechanism in the compiler. Instead of using function pointer types (`PostCallHook`, `FinalizeHook`) and a struct to hold them (`CallHooks`), it introduces a trait `RtlCompilerHook` with default implementations for `post_call` and `finalize`. This change aligns with Rust's idiomatic way of handling extension points and allows for more flexible and extensible compiler behavior. The `TypeChecker` now holds a map of `Rc<dyn RtlCompilerHook>`, enabling different RTL functions to register their specific compiler hooks. The `SeriesHook` and `PushHook` structs are introduced to demonstrate this new pattern.
73 lines
2.9 KiB
Rust
73 lines
2.9 KiB
Rust
use std::collections::HashMap;
|
|
use std::rc::Rc;
|
|
|
|
use crate::ast::diagnostics::Diagnostics;
|
|
use crate::ast::nodes::{Address, NodeKind, TypedNode, TypedPhase, VirtualId};
|
|
use crate::ast::types::StaticType;
|
|
|
|
/// Gives a compiler hook access to the type-checker's core inference operations
|
|
/// and scope slot types without depending on the concrete `TypeChecker` type
|
|
/// (avoids a circular module dependency).
|
|
pub trait InferenceAccess {
|
|
/// Allocate a fresh unique `TypeVar`.
|
|
fn fresh_var(&self) -> StaticType;
|
|
|
|
/// Unify two types, recording the substitution. Emits a diagnostic on conflict.
|
|
fn unify(&self, a: StaticType, b: StaticType, diag: &mut Diagnostics);
|
|
|
|
/// Directly bind a `TypeVar` ID to a resolved type in the substitution map.
|
|
fn bind_typevar(&self, id: u32, ty: StaticType);
|
|
|
|
/// Apply the current substitution to a type, resolving all known `TypeVar`s.
|
|
fn apply_subst_ty(&self, ty: StaticType) -> StaticType;
|
|
|
|
/// Int/Float numeric-widening rule. Returns the promoted type, or `None` if
|
|
/// the combination is not a widening pair.
|
|
fn try_numeric_widen(&self, a: &StaticType, b: &StaticType) -> Option<StaticType>;
|
|
|
|
/// Record-field promotion rule. Returns the promoted record type when one record
|
|
/// is a strict widening of the other, or `None` otherwise.
|
|
fn try_record_promote(&self, a: &StaticType, b: &StaticType) -> Option<StaticType>;
|
|
|
|
/// Read the raw (unsubstituted) type stored in a scope slot.
|
|
/// Used by hooks that need to recover the original `TypeVar` ID after
|
|
/// the substitution has already resolved it to a concrete type.
|
|
fn get_slot_type(&self, addr: Address<VirtualId>) -> StaticType;
|
|
}
|
|
|
|
/// Extension point that lets RTL functions participate in the compiler's
|
|
/// type-inference and AST-finalization passes without hardcoding symbol
|
|
/// names anywhere in the compiler core.
|
|
///
|
|
/// Each RTL function that needs custom type-level behaviour (e.g. `series`,
|
|
/// `push`) implements this trait. Hooks are registered by global slot index
|
|
/// during RTL bootstrap and dispatched automatically by the type checker.
|
|
///
|
|
/// Both methods have no-op defaults so that implementors only override what
|
|
/// they need.
|
|
pub trait RtlCompilerHook {
|
|
/// Called after the call's return type is resolved during type inference.
|
|
/// May replace the return type and/or perform unification side-effects.
|
|
fn post_call(
|
|
&self,
|
|
_args: &TypedNode,
|
|
ret_ty: StaticType,
|
|
_ctx: &dyn InferenceAccess,
|
|
_diag: &mut Diagnostics,
|
|
) -> StaticType {
|
|
ret_ty
|
|
}
|
|
|
|
/// Called during AST finalization.
|
|
/// Returns `Some(new_kind)` to rewrite the node, or `None` to keep the original.
|
|
fn finalize(
|
|
&self,
|
|
_callee: Rc<TypedNode>,
|
|
_args: Rc<TypedNode>,
|
|
_node_ty: &StaticType,
|
|
_subst: &HashMap<u32, StaticType>,
|
|
) -> Option<NodeKind<TypedPhase>> {
|
|
None
|
|
}
|
|
}
|