Add PartialEq to BoundKind and Value
Implement PartialEq for BoundKind to allow for structural equality checks during optimization. This enables the optimizer to terminate early when a node no longer changes. Also, implement PartialEq for Value to facilitate comparisons between different Value variants.
This commit is contained in:
@@ -114,6 +114,62 @@ pub enum BoundKind<T = ()> {
|
||||
Extension(Box<dyn BoundExtension<T>>),
|
||||
}
|
||||
|
||||
impl<T> PartialEq for BoundKind<T>
|
||||
where T: PartialEq {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(BoundKind::Nop, BoundKind::Nop) => true,
|
||||
(BoundKind::Constant(a), BoundKind::Constant(b)) => a == b,
|
||||
(BoundKind::Parameter { name: na, slot: sa }, BoundKind::Parameter { name: nb, slot: sb }) => {
|
||||
na == nb && sa == sb
|
||||
}
|
||||
(BoundKind::Get { addr: aa, name: na }, BoundKind::Get { addr: ab, name: nb }) => {
|
||||
aa == ab && na == nb
|
||||
}
|
||||
(BoundKind::Set { addr: aa, value: va }, BoundKind::Set { addr: ab, value: vb }) => {
|
||||
aa == ab && va == vb
|
||||
}
|
||||
(BoundKind::DefLocal { name: na, slot: sa, value: va, captured_by: ca },
|
||||
BoundKind::DefLocal { name: nb, slot: sb, value: vb, captured_by: cb }) => {
|
||||
na == nb && sa == sb && va == vb && ca == cb
|
||||
}
|
||||
(BoundKind::If { cond: ca, then_br: ta, else_br: ea },
|
||||
BoundKind::If { cond: cb, then_br: tb, else_br: eb }) => {
|
||||
ca == cb && ta == tb && ea == eb
|
||||
}
|
||||
(BoundKind::DefGlobal { name: na, global_index: ga, value: va },
|
||||
BoundKind::DefGlobal { name: nb, global_index: gb, value: vb }) => {
|
||||
na == nb && ga == gb && va == vb
|
||||
}
|
||||
(BoundKind::Lambda { params: pa, upvalues: ua, body: ba, positional_count: pca },
|
||||
BoundKind::Lambda { params: pb, upvalues: ub, body: bb, positional_count: pcb }) => {
|
||||
pa == pb && ua == ub && ba == bb && pca == pcb
|
||||
}
|
||||
(BoundKind::Call { callee: ca, args: aa }, BoundKind::Call { callee: cb, args: ab }) => {
|
||||
ca == cb && aa == ab
|
||||
}
|
||||
(BoundKind::TailCall { callee: ca, args: aa }, BoundKind::TailCall { callee: cb, args: ab }) => {
|
||||
ca == cb && aa == ab
|
||||
}
|
||||
(BoundKind::Block { exprs: ea }, BoundKind::Block { exprs: eb }) => {
|
||||
ea == eb
|
||||
}
|
||||
(BoundKind::Tuple { elements: ea }, BoundKind::Tuple { elements: eb }) => {
|
||||
ea == eb
|
||||
}
|
||||
(BoundKind::Record { fields: fa }, BoundKind::Record { fields: fb }) => {
|
||||
fa == fb
|
||||
}
|
||||
(BoundKind::Expansion { original_call: oa, bound_expanded: ba },
|
||||
BoundKind::Expansion { original_call: ob, bound_expanded: bb }) => {
|
||||
Rc::ptr_eq(oa, ob) && ba == bb
|
||||
}
|
||||
(BoundKind::Extension(_), BoundKind::Extension(_)) => false, // Currently no equality for extensions
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field in a Record literal (Key-Value pair)
|
||||
pub type RecordField<T> = (BoundNode<T>, BoundNode<T>);
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ impl Optimizer {
|
||||
let mut current = node;
|
||||
for _ in 0..self.max_passes {
|
||||
let next = self.visit_node(current.clone());
|
||||
// TODO: Structural equality check to stop early
|
||||
if next == current {
|
||||
break;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
current
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ impl From<&str> for Symbol {
|
||||
}
|
||||
|
||||
/// A generic AST Node wrapper to preserve identity and metadata
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Node<K, T = ()> {
|
||||
pub identity: Identity,
|
||||
pub kind: K,
|
||||
|
||||
+24
-1
@@ -59,7 +59,7 @@ pub trait Object: fmt::Debug {
|
||||
pub type ValueList = Rc<Vec<Value>>;
|
||||
|
||||
/// Internal storage for Records to allow sharing schema (keys) between instances.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RecordData {
|
||||
/// Names for slots.
|
||||
pub keys: Rc<Vec<Keyword>>,
|
||||
@@ -85,6 +85,29 @@ pub enum Value {
|
||||
TailCallRequest(Box<(Rc<dyn Object>, Vec<Value>)>), // Internal: For TCO (Boxed to keep Value small)
|
||||
}
|
||||
|
||||
impl PartialEq for Value {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Value::Void, Value::Void) => true,
|
||||
(Value::Bool(a), Value::Bool(b)) => a == b,
|
||||
(Value::Int(a), Value::Int(b)) => a == b,
|
||||
(Value::Float(a), Value::Float(b)) => a == b,
|
||||
(Value::DateTime(a), Value::DateTime(b)) => a == b,
|
||||
(Value::Text(a), Value::Text(b)) => a == b,
|
||||
(Value::Keyword(a), Value::Keyword(b)) => a == b,
|
||||
(Value::Tuple(a), Value::Tuple(b)) => a == b,
|
||||
(Value::Record(a), Value::Record(b)) => a == b,
|
||||
(Value::Function(a), Value::Function(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::Object(a), Value::Object(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::Cell(a), Value::Cell(b)) => Rc::ptr_eq(a, b),
|
||||
(Value::TailCallRequest(a), Value::TailCallRequest(b)) => {
|
||||
Rc::ptr_eq(&a.0, &b.0) && a.1 == b.1
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Signature {
|
||||
pub params: StaticType,
|
||||
|
||||
Reference in New Issue
Block a user