Refactor call hooks to use trait objects
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.
This commit is contained in:
@@ -5,8 +5,8 @@ use crate::ast::diagnostics::Diagnostics;
|
||||
use crate::ast::nodes::{Address, NodeKind, TypedNode, TypedPhase, VirtualId};
|
||||
use crate::ast::types::StaticType;
|
||||
|
||||
/// Gives a call-hook access to the type-checker's core inference operations and
|
||||
/// scope slot types without depending on the concrete `TypeChecker` type
|
||||
/// 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`.
|
||||
@@ -35,29 +35,38 @@ pub trait InferenceAccess {
|
||||
fn get_slot_type(&self, addr: Address<VirtualId>) -> StaticType;
|
||||
}
|
||||
|
||||
/// Called after the call's return type is resolved.
|
||||
/// May replace the return type and/or perform unification side-effects (e.g. push).
|
||||
pub type PostCallHook = fn(
|
||||
args: &TypedNode,
|
||||
ret_ty: StaticType,
|
||||
ctx: &dyn InferenceAccess,
|
||||
diag: &mut Diagnostics,
|
||||
) -> StaticType;
|
||||
|
||||
/// Called during AST finalization.
|
||||
/// Returns `Some(new_kind)` to rewrite the node, or `None` to keep the original.
|
||||
pub type FinalizeHook = fn(
|
||||
callee: Rc<TypedNode>,
|
||||
args: Rc<TypedNode>,
|
||||
node_ty: &StaticType,
|
||||
subst: &HashMap<u32, StaticType>,
|
||||
) -> Option<NodeKind<TypedPhase>>;
|
||||
|
||||
/// Hooks attached to a specific RTL function slot.
|
||||
/// Enables type-inference extensions and AST rewrites without hardcoding symbol
|
||||
/// 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.
|
||||
#[derive(Default)]
|
||||
pub struct CallHooks {
|
||||
pub post_call: Option<PostCallHook>,
|
||||
pub finalize: Option<FinalizeHook>,
|
||||
///
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user