Fix: Simplify type checker and optimizer

Removes unnecessary lambda wrapping in the type checking pipeline.
Adds optimization logic for `NodeKind::Program` to handle sequences of
expressions.
Removes debug print statements from the type checker.
This commit is contained in:
2026-03-31 16:42:13 +02:00
parent 19008b5d3e
commit 90f9afa0fd
4 changed files with 33 additions and 56 deletions
+29
View File
@@ -792,6 +792,35 @@ impl Optimizer {
node.ty.clone(), node.ty.clone(),
) )
} }
NodeKind::Program { exprs } => {
let mut new_exprs = Vec::with_capacity(exprs.len());
let mut changed = false;
for e in exprs {
let opt = self.visit_node(e.clone(), sub, path);
if !Rc::ptr_eq(&opt, e) {
changed = true;
}
new_exprs.push(opt);
}
if new_exprs.len() == 1 {
return new_exprs.pop().unwrap();
}
if !changed {
return node_rc;
}
let last_ty = new_exprs
.last()
.map(|e| e.ty.original.ty.clone())
.unwrap_or(StaticType::Void);
(
NodeKind::Program { exprs: new_exprs },
refreshed_metrics(&node.ty, last_ty),
)
}
k => (k.clone(), node.ty.clone()), k => (k.clone(), node.ty.clone()),
}; };
-13
View File
@@ -529,20 +529,17 @@ impl TypeChecker {
let param_hint_ty = StaticType::Tuple( let param_hint_ty = StaticType::Tuple(
(0..positional_count.unwrap_or(0)).map(|_| self.fresh_var()).collect(), (0..positional_count.unwrap_or(0)).map(|_| self.fresh_var()).collect(),
); );
eprintln!("[TC] Lambda check_node: positional_count={:?} param_hint={}", positional_count, param_hint_ty.display_compact());
let params_typed = self.check_params( let params_typed = self.check_params(
params.as_ref(), params.as_ref(),
&param_hint_ty, &param_hint_ty,
&mut lambda_ctx, &mut lambda_ctx,
diag, diag,
); );
eprintln!("[TC] Lambda params_typed.ty={}", params_typed.ty.display_compact());
lambda_ctx.current_params_ty = Some(params_typed.ty.clone()); lambda_ctx.current_params_ty = Some(params_typed.ty.clone());
let body_typed = self.check_node(body, &mut lambda_ctx, diag); let body_typed = self.check_node(body, &mut lambda_ctx, diag);
let ret_ty = body_typed.ty.clone(); let ret_ty = body_typed.ty.clone();
eprintln!("[TC] Lambda body ret_ty={}", ret_ty.display_compact());
let fn_ty = StaticType::Function(Box::new(Signature { let fn_ty = StaticType::Function(Box::new(Signature {
params: params_typed.ty.clone(), params: params_typed.ty.clone(),
@@ -563,9 +560,7 @@ impl TypeChecker {
} }
NodeKind::Call { callee, args } => { NodeKind::Call { callee, args } => {
eprintln!("[TC] Call: checking callee...");
let callee_typed = self.check_node(callee, ctx, diag); let callee_typed = self.check_node(callee, ctx, diag);
eprintln!("[TC] Call: callee_typed.ty={}", callee_typed.ty.display_compact());
let args_typed = if let NodeKind::Tuple { elements } = &args.kind { let args_typed = if let NodeKind::Tuple { elements } = &args.kind {
let arg_count = elements.len(); let arg_count = elements.len();
@@ -624,7 +619,6 @@ impl TypeChecker {
self.check_node(args, ctx, diag) self.check_node(args, ctx, diag)
}; };
eprintln!("[TC] Call: args_typed.ty={}", args_typed.ty.display_compact());
let mut ret_ty = match callee_typed.ty.resolve_call(&args_typed.ty) { let mut ret_ty = match callee_typed.ty.resolve_call(&args_typed.ty) {
Some(ty) => ty, Some(ty) => ty,
None => { None => {
@@ -688,16 +682,9 @@ impl TypeChecker {
if let StaticType::Function(sig) = &callee_typed.ty if let StaticType::Function(sig) = &callee_typed.ty
&& Self::has_typevar_component(&sig.params) && Self::has_typevar_component(&sig.params)
{ {
eprintln!("[TC] HM10: unify params={} with args={}", sig.params.display_compact(), args_typed.ty.display_compact());
let params = sig.params.clone(); let params = sig.params.clone();
self.unify(params, args_typed.ty.clone(), diag); self.unify(params, args_typed.ty.clone(), diag);
ret_ty = Self::apply_subst(ret_ty, &self.subst.borrow()); ret_ty = Self::apply_subst(ret_ty, &self.subst.borrow());
eprintln!("[TC] HM10: after unify ret_ty={}", ret_ty.display_compact());
} else {
eprintln!("[TC] HM10: SKIPPED (callee_ty={}, has_typevar={})",
callee_typed.ty.display_compact(),
if let StaticType::Function(sig) = &callee_typed.ty { Self::has_typevar_component(&sig.params) } else { false }
);
} }
// Dispatch compiler hooks registered by the RTL (keyed by global slot index). // Dispatch compiler hooks registered by the RTL (keyed by global slot index).
-2
View File
@@ -70,7 +70,6 @@ impl TypeChecker {
) -> TypedNode { ) -> TypedNode {
match &node.kind { match &node.kind {
NodeKind::Lambda { params, body, info } => { NodeKind::Lambda { params, body, info } => {
eprintln!("[TC] check_node_as_bound: Lambda entry");
let upvalues = &info.upvalues; let upvalues = &info.upvalues;
let positional_count = info.positional_count; let positional_count = info.positional_count;
@@ -116,7 +115,6 @@ impl TypeChecker {
} }
} }
NodeKind::Block { .. } | NodeKind::Program { .. } => { NodeKind::Block { .. } | NodeKind::Program { .. } => {
eprintln!("[TC] check_node_as_bound: Block/Program entry");
let mut ctx = TypeContext::new(64, vec![], &self.root_types, None); let mut ctx = TypeContext::new(64, vec![], &self.root_types, None);
self.check_node(node, &mut ctx, diag) self.check_node(node, &mut ctx, diag)
} }
+4 -41
View File
@@ -12,7 +12,7 @@ use std::rc::Rc;
use crate::ast::nodes::{ use crate::ast::nodes::{
Address, AnalyzedNode, ExecNode, GlobalAnalyzedRegistry, GlobalFunctionRegistry, GlobalIdx, Address, AnalyzedNode, ExecNode, GlobalAnalyzedRegistry, GlobalFunctionRegistry, GlobalIdx,
LambdaBinding, Node, NodeKind, VirtualId, Node, NodeKind, VirtualId,
}; };
use crate::ast::compiler::dumper::Dumper; use crate::ast::compiler::dumper::Dumper;
use crate::ast::compiler::lambda_collector::LambdaCollector; use crate::ast::compiler::lambda_collector::LambdaCollector;
@@ -447,38 +447,11 @@ impl Environment {
typed typed
} }
/// Wraps a bound AST in a parameterless lambda (unless it already is one). /// Full compilation pipeline: expand → bind → type-check.
fn wrap_as_lambda(&self, bound_ast: Node<BoundPhase>) -> Node<BoundPhase> {
if let NodeKind::Lambda { .. } = bound_ast.kind {
bound_ast
} else {
Node {
identity: bound_ast.identity.clone(),
kind: NodeKind::Lambda {
params: Rc::new(Node {
identity: bound_ast.identity.clone(),
kind: NodeKind::Tuple { elements: vec![] },
ty: (),
comments: Rc::from([]),
}),
body: Rc::new(bound_ast),
info: LambdaBinding {
upvalues: vec![],
positional_count: Some(0),
},
},
ty: (),
comments: Rc::from([]),
}
}
}
/// Full compilation pipeline: expand → bind → wrap → type-check.
fn compile_pipeline(&self, syntax_ast: SyntaxNode, diagnostics: &mut Diagnostics) -> Option<TypedNode> { fn compile_pipeline(&self, syntax_ast: SyntaxNode, diagnostics: &mut Diagnostics) -> Option<TypedNode> {
let expanded = self.expand(syntax_ast, diagnostics)?; let expanded = self.expand(syntax_ast, diagnostics)?;
let bound = self.bind_and_update(&expanded, diagnostics)?; let bound = self.bind_and_update(&expanded, diagnostics)?;
let wrapped = self.wrap_as_lambda(bound); let typed = self.type_check(&bound, diagnostics);
let typed = self.type_check(&wrapped, diagnostics);
Some(typed) Some(typed)
} }
@@ -737,17 +710,7 @@ impl Environment {
} }
let mut parser = Parser::new(source); let mut parser = Parser::new(source);
let syntax_ast = parser.parse_expression(); let syntax_ast = parser.parse_program();
if !parser.at_eof() {
parser
.diagnostics
.push_error("Unexpected trailing expressions in script.", None);
return CompilationResult {
ast: None,
diagnostics: parser.diagnostics,
};
}
let mut diagnostics = parser.diagnostics; let mut diagnostics = parser.diagnostics;
let typed_ast = self.compile_pipeline(syntax_ast, &mut diagnostics); let typed_ast = self.compile_pipeline(syntax_ast, &mut diagnostics);