Impl Bind Pattern

Posted 2023-04-17 13:44:34 ‐ 1 min read

The Impl Bind Pattern allows us to create a new type that represents another type, but binds a parameter to all the methods in this implementation.

For example:

pub struct ControlFlowGraph(/*...*/);

impl ControlFlowGraph {
    fn dominance_frontier(
        &self,
        content: &ir::FunctionDefinition,
        bb_index: usize,
    ) -> &[usize];

    fn basic_block_index_by_name(&self, content: &ir::FunctionDefinition, name: &str) -> usize;
    fn basic_block_name_by_index(
        &self,
        content: &ir::FunctionDefinition,
        index: usize,
    ) -> &str;
    fn may_pass_blocks(
        &self,
        content: &ir::FunctionDefinition,
        from: usize,
        to: usize,
    ) -> Ref<Vec<usize>>;
}

pub struct BindedControlFlowGraph<'item, 'bind: 'item> {
    bind_on: &'bind FunctionDefinition,
    item: &'item ControlFlowGraph,
}

impl<'item, 'bind: 'item> BindedControlFlowGraph<'item, 'bind> {
    pub fn dominance_frontier(&self, bb_index: usize) -> &[usize] {
        self.item.dominance_frontier(self.bind_on, bb_index)
    }
    pub fn basic_block_index_by_name(&self, name: &str) -> usize {
        self.item.basic_block_index_by_name(self.bind_on, name)
    }
    pub fn basic_block_name_by_index(&self, index: usize) -> &str {
        self.item.basic_block_name_by_index(self.bind_on, index)
    }
    pub fn may_pass_blocks(&self, from: usize, to: usize) -> Ref<Vec<usize>> {
        self.item.may_pass_blocks(self.bind_on, from, to)
    }
}

Motivation

Use the example above, ControlFlowGraph is used to analyze the control flow of a function. It uses interior mutability to cache information about the control flow. We use on_action to update or invalidate the cache and use the other methods to query the information.

By letting the BindedControlFlowGraph store a reference to FunctionDefinition and using it instead of ControlFlowGraph in other places, we prevent the FunctionDefinition from being edited when the BindedControlFlowGraph is in scope and save a parameter passing when using.