diff --git a/src/actions.rs b/src/actions.rs index a703fe36..0102eba4 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -392,10 +392,20 @@ impl EGraph { function.remove(args, self.timestamp); } Change::Subsume => { - if function.decl.merge.is_some() { + if function.decl.subtype != FunctionSubtype::Constructor + && function.decl.subtype != FunctionSubtype::Relation + { return Err(Error::SubsumeMergeError(*f)); } - function.subsume(args); + function + .nodes + .insert_and_merge(args, self.timestamp, true, |old| { + old.unwrap_or_else(|| Value { + #[cfg(debug_assertions)] + tag: function.schema.output.name(), + bits: self.unionfind.make_set(), + }) + }); } } stack.truncate(new_len); diff --git a/src/function/mod.rs b/src/function/mod.rs index 22bf4c81..60073598 100644 --- a/src/function/mod.rs +++ b/src/function/mod.rs @@ -212,11 +212,6 @@ impl Function { res } - /// Mark the given inputs as subsumed. - pub fn subsume(&mut self, inputs: &[Value]) { - self.nodes.get_mut(inputs).unwrap().subsumed = true; - } - /// Return a column index that contains (a superset of) the offsets for the /// given column. This method can return nothing if the indexes available /// contain too many irrelevant offsets. diff --git a/src/function/table.rs b/src/function/table.rs index 78317024..7e59899c 100644 --- a/src/function/table.rs +++ b/src/function/table.rs @@ -108,13 +108,6 @@ impl Table { Some(&self.vals[off].1) } - pub(crate) fn get_mut(&mut self, inputs: &[Value]) -> Option<&mut TupleOutput> { - let hash: u64 = hash_values(inputs); - let &TableOffset { off, .. } = self.table.find(hash, self.search_for(hash, inputs))?; - debug_assert!(self.vals[off].0.live()); - Some(&mut self.vals[off].1) - } - /// Insert the given data into the table at the given timestamp. Return the /// previous value, if there was one. pub(crate) fn insert(&mut self, inputs: &[Value], out: Value, ts: u32) -> Option { diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 6e3085d0..0f8d8354 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -350,8 +350,9 @@ fn test_subsume() { } #[test] -fn test_subsume_primitive() { - // Test that we can subsume a primitive +fn test_subsume_custom() { + // Test that we can't subsume a custom function + // Only relations and constructors are allowed to be subsumed let mut egraph = EGraph::default(); let res = egraph.parse_and_run_program( @@ -362,6 +363,29 @@ fn test_subsume_primitive() { (subsume (one)) "#, ); + assert!(res.is_err()); +} + +#[test] +fn test_subsume_ok() { + let mut egraph = EGraph::default(); + let res = egraph.parse_and_run_program( + None, + r#" + (sort E) + (constructor one () E) + (constructor two () E) + (one) + (subsume (one)) + ;; subsuming a non-existent tuple + (subsume (two)) + + (relation R (i64)) + (R 1) + (subsume (R 1)) + (subsume (R 2)) + "#, + ); assert!(res.is_ok()); } @@ -432,7 +456,7 @@ fn test_serialize_subsume_status() { None, egglog::SerializedNode::Function { name: ("a").into(), - offset: 0, + offset: 1, }, ); let b_id = egraph.to_node_id(