Remove IndexElementFn and series_element_type
The `IndexElementFn` trait and its associated `series_element_type` function have been removed. The `TypeChecker` now directly inspects the `StaticType::Series` variant to extract the element type when propagating index constraints. This simplifies the type-checking logic by removing an unnecessary layer of indirection and adhering to the project rule of keeping the AST simple and pushing complexity into the system.
This commit is contained in:
@@ -35,16 +35,6 @@ pub trait InferenceAccess {
|
|||||||
fn get_slot_type(&self, addr: Address<VirtualId>) -> StaticType;
|
fn get_slot_type(&self, addr: Address<VirtualId>) -> StaticType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps a concrete type to its element type for index-constraint propagation.
|
|
||||||
/// Called by `bind_var` when a TypeVar with an index constraint is bound.
|
|
||||||
///
|
|
||||||
/// Returns `Some(elem_ty)` if `ty` supports integer-index access (e.g. `Series`),
|
|
||||||
/// or `None` for all non-indexable types.
|
|
||||||
///
|
|
||||||
/// Register the appropriate implementation via `TypeChecker::new`. Each indexable
|
|
||||||
/// type (Series, and in future Stream) contributes a match arm here.
|
|
||||||
pub type IndexElementFn = fn(&StaticType) -> Option<StaticType>;
|
|
||||||
|
|
||||||
/// Called after the call's return type is resolved.
|
/// Called after the call's return type is resolved.
|
||||||
/// May replace the return type and/or perform unification side-effects (e.g. push).
|
/// May replace the return type and/or perform unification side-effects (e.g. push).
|
||||||
pub type PostCallHook = fn(
|
pub type PostCallHook = fn(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::ast::compiler::call_hooks::{CallHooks, InferenceAccess, IndexElementFn};
|
use crate::ast::compiler::call_hooks::{CallHooks, InferenceAccess};
|
||||||
use crate::ast::nodes::{
|
use crate::ast::nodes::{
|
||||||
Address, AssignBinding, BoundLike, BoundPhase, DefBinding, IdentifierBinding, LambdaBinding,
|
Address, AssignBinding, BoundLike, BoundPhase, DefBinding, IdentifierBinding, LambdaBinding,
|
||||||
Node, NodeKind, TypedNode, TypedPhase, VirtualId,
|
Node, NodeKind, TypedNode, TypedPhase, VirtualId,
|
||||||
@@ -182,12 +182,8 @@ pub struct TypeChecker {
|
|||||||
/// the series lookback pattern `(s 0)` — we record the pairing here instead
|
/// the series lookback pattern `(s 0)` — we record the pairing here instead
|
||||||
/// of eagerly unifying `TypeVar = Series(elem)`. The constraint is evaluated
|
/// of eagerly unifying `TypeVar = Series(elem)`. The constraint is evaluated
|
||||||
/// lazily in `bind_var`: when the callee TypeVar is bound to a concrete type,
|
/// lazily in `bind_var`: when the callee TypeVar is bound to a concrete type,
|
||||||
/// `index_element_fn` determines the element type (if any) and propagates it.
|
/// the element type is extracted directly from the `Series` variant.
|
||||||
index_constraints: std::cell::RefCell<HashMap<u32, u32>>,
|
index_constraints: std::cell::RefCell<HashMap<u32, u32>>,
|
||||||
/// Resolves the element type of an indexable type for index-constraint propagation.
|
|
||||||
/// Registered at construction; keeps the type-checker core free of type-specific logic.
|
|
||||||
/// See [`IndexElementFn`] for the contract.
|
|
||||||
index_element_fn: IndexElementFn,
|
|
||||||
/// Type-inference and finalization hooks keyed by global slot index.
|
/// Type-inference and finalization hooks keyed by global slot index.
|
||||||
/// Populated from the frozen RTL snapshot; empty for non-RTL call sites.
|
/// Populated from the frozen RTL snapshot; empty for non-RTL call sites.
|
||||||
call_hooks: Rc<HashMap<u32, CallHooks>>,
|
call_hooks: Rc<HashMap<u32, CallHooks>>,
|
||||||
@@ -197,14 +193,12 @@ impl TypeChecker {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
root_types: Rc<std::cell::RefCell<Vec<StaticType>>>,
|
root_types: Rc<std::cell::RefCell<Vec<StaticType>>>,
|
||||||
call_hooks: Rc<HashMap<u32, CallHooks>>,
|
call_hooks: Rc<HashMap<u32, CallHooks>>,
|
||||||
index_element_fn: IndexElementFn,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
root_types,
|
root_types,
|
||||||
var_counter: Cell::new(0),
|
var_counter: Cell::new(0),
|
||||||
subst: std::cell::RefCell::new(HashMap::new()),
|
subst: std::cell::RefCell::new(HashMap::new()),
|
||||||
index_constraints: std::cell::RefCell::new(HashMap::new()),
|
index_constraints: std::cell::RefCell::new(HashMap::new()),
|
||||||
index_element_fn,
|
|
||||||
call_hooks,
|
call_hooks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,17 +211,17 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Binds a TypeVar to a concrete type in the substitution, then propagates
|
/// Binds a TypeVar to a concrete type in the substitution, then propagates
|
||||||
/// any pending index-call constraints registered by Step 9.
|
/// any pending index-call constraints registered for the series lookback pattern.
|
||||||
///
|
///
|
||||||
/// If `index_constraints[id]` is set and `index_element_fn` returns an element
|
/// When `index_constraints[id]` is set and `ty` is a `Series`, the result TypeVar
|
||||||
/// type for `ty`, the result TypeVar is bound to that element type — connecting
|
/// is bound to the element type — connecting the callee TypeVar to its element type
|
||||||
/// the callee TypeVar to its element type without the eager over-constraint of
|
/// without the eager over-constraint of unification. Non-indexable types leave the
|
||||||
/// unification. For non-indexable types the result TypeVar stays unresolved.
|
/// result TypeVar unresolved.
|
||||||
fn bind_var(&self, id: u32, ty: StaticType) {
|
fn bind_var(&self, id: u32, ty: StaticType) {
|
||||||
self.subst.borrow_mut().insert(id, ty.clone());
|
self.subst.borrow_mut().insert(id, ty.clone());
|
||||||
let ret_id = self.index_constraints.borrow().get(&id).copied();
|
let ret_id = self.index_constraints.borrow().get(&id).copied();
|
||||||
if let (Some(ret_id), Some(elem_ty)) = (ret_id, (self.index_element_fn)(&ty)) {
|
if let (Some(ret_id), StaticType::Series(elem)) = (ret_id, &ty) {
|
||||||
self.subst.borrow_mut().insert(ret_id, elem_ty);
|
self.subst.borrow_mut().insert(ret_id, *elem.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ use crate::ast::compiler::macros::{MacroEvaluator, MacroExpander, MacroRegistry}
|
|||||||
use crate::ast::compiler::optimizer::Optimizer;
|
use crate::ast::compiler::optimizer::Optimizer;
|
||||||
use crate::ast::compiler::specializer::{FunctionRegistry, MonoCache, RtlLookupFunc, Specializer};
|
use crate::ast::compiler::specializer::{FunctionRegistry, MonoCache, RtlLookupFunc, Specializer};
|
||||||
use crate::ast::rtl::{self, intrinsics};
|
use crate::ast::rtl::{self, intrinsics};
|
||||||
use crate::ast::rtl::series::series_element_type;
|
|
||||||
use crate::ast::rtl::docs::{PipelineGenerator, RtlDocEntry, RtlRegistration};
|
use crate::ast::rtl::docs::{PipelineGenerator, RtlDocEntry, RtlRegistration};
|
||||||
use crate::ast::types::{
|
use crate::ast::types::{
|
||||||
CommentLine, NativeFunction, NodeIdentity, Purity, SourceLocation, StaticType, Value,
|
CommentLine, NativeFunction, NodeIdentity, Purity, SourceLocation, StaticType, Value,
|
||||||
@@ -133,7 +132,7 @@ impl MacroEvaluator for RuntimeMacroEvaluator {
|
|||||||
|
|
||||||
let (bound_ast, captures, _, _) = Binder::bind_root(initial_scopes, initial_slot_count, self.fixed_scope_idx, node, &mut diag)?;
|
let (bound_ast, captures, _, _) = Binder::bind_root(initial_scopes, initial_slot_count, self.fixed_scope_idx, node, &mut diag)?;
|
||||||
let bound_ast = CapturePass::apply(bound_ast, &captures);
|
let bound_ast = CapturePass::apply(bound_ast, &captures);
|
||||||
let checker = TypeChecker::new(self.root_types.clone(), Rc::clone(&self.call_hooks), series_element_type);
|
let checker = TypeChecker::new(self.root_types.clone(), Rc::clone(&self.call_hooks));
|
||||||
let typed_ast = checker.check(&bound_ast, &[], &mut diag);
|
let typed_ast = checker.check(&bound_ast, &[], &mut diag);
|
||||||
|
|
||||||
if diag.has_errors() {
|
if diag.has_errors() {
|
||||||
@@ -481,7 +480,7 @@ impl Environment {
|
|||||||
|
|
||||||
LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut());
|
LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut());
|
||||||
|
|
||||||
let checker = TypeChecker::new(self.root_types.clone(), Rc::clone(&self.rtl.call_hooks), series_element_type);
|
let checker = TypeChecker::new(self.root_types.clone(), Rc::clone(&self.rtl.call_hooks));
|
||||||
let wrapped_ast = if let NodeKind::Lambda { .. } = bound_ast.kind {
|
let wrapped_ast = if let NodeKind::Lambda { .. } = bound_ast.kind {
|
||||||
bound_ast
|
bound_ast
|
||||||
} else {
|
} else {
|
||||||
@@ -835,7 +834,7 @@ impl Environment {
|
|||||||
arg_types: &[StaticType]|
|
arg_types: &[StaticType]|
|
||||||
-> Result<(Value, StaticType), String> {
|
-> Result<(Value, StaticType), String> {
|
||||||
let mut diag = Diagnostics::new();
|
let mut diag = Diagnostics::new();
|
||||||
let checker = TypeChecker::new(root_types.clone(), Rc::clone(&call_hooks), series_element_type);
|
let checker = TypeChecker::new(root_types.clone(), Rc::clone(&call_hooks));
|
||||||
|
|
||||||
// Monomorphization: re-type-check the function template with the concrete
|
// Monomorphization: re-type-check the function template with the concrete
|
||||||
// call-site argument types, producing a specialized TypedNode.
|
// call-site argument types, producing a specialized TypedNode.
|
||||||
|
|||||||
@@ -15,21 +15,6 @@ use crate::ast::types::{NativeFunction, NodeIdentity, Purity, Signature, SourceL
|
|||||||
// 4. Type-Inference Hooks (registered via RTL bootstrap, no name coupling)
|
// 4. Type-Inference Hooks (registered via RTL bootstrap, no name coupling)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/// Index-element hook for the `Series` type.
|
|
||||||
///
|
|
||||||
/// Returns the element type of a `Series(inner)`, or `None` for all other types.
|
|
||||||
/// Registered with `TypeChecker` so that the core type-checker remains agnostic
|
|
||||||
/// about which concrete types support integer-index access.
|
|
||||||
///
|
|
||||||
/// When `Stream` (or future indexable types) is added, extend this function
|
|
||||||
/// with additional match arms rather than touching the type-checker.
|
|
||||||
pub(crate) fn series_element_type(ty: &StaticType) -> Option<StaticType> {
|
|
||||||
match ty {
|
|
||||||
StaticType::Series(inner) => Some(*inner.clone()),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Post-call hook for `(series n)`.
|
/// Post-call hook for `(series n)`.
|
||||||
/// Replaces the `Series(Any)` return type with a fresh TypeVar so that
|
/// Replaces the `Series(Any)` return type with a fresh TypeVar so that
|
||||||
/// subsequent `push` calls can unify the element type (HM inference).
|
/// subsequent `push` calls can unify the element type (HM inference).
|
||||||
|
|||||||
Reference in New Issue
Block a user