Cannot borrow variable as mutable within loop

45 views Asked by At

I have the following file in my interpreter for a personal programming language. The program itself is meant to take the output of the parser and convert it into an active parse tree.

use crate::errors::{ActiveParserError, FileLocation};
use crate::parser::{Term, Type};

use std::collections::HashMap;

pub enum ActiveParse {
    File { active_terms: Vec<ActiveParse> },
    Function {},
    Class {},
    VarDeclation,
    VarUpdate,
    Return,
    UpdateVar,
    If,
    Loop,
    ReadLn,
    Break,
    Continue,
    Call,
}

struct VarRegistry<'a> {
    tree_connection: VarRegistryTreeConnection<'a>,
    object: HashMap<u32, ObjectOption<'a>>,
}

impl<'a> VarRegistry<'a> {
    fn new() -> Self {
        Self {
            tree_connection: VarRegistryTreeConnection::Base { uid_counter: 0 },
            object: HashMap::new(),
        }
    }

    fn create_child(&'a mut self) -> Self {
        Self {
            tree_connection: VarRegistryTreeConnection::Child { parent: self },
            object: HashMap::new(),
        }
    }

    fn add_var(&mut self, name: String, _type: Type) {
        todo!()
    }

    fn add_typevar(&mut self, name: String) {
        todo!()
    }

    fn uid(&mut self) -> u32 {
        match &mut self.tree_connection {
            VarRegistryTreeConnection::Child { parent } => return parent.uid(),
            VarRegistryTreeConnection::Base { uid_counter } => {
                *uid_counter += 1;
                return *uid_counter;
            }
        }
    }
}
enum ObjectOption<'a> {
    Var {
        var_type: String,
        name: String,
    },
    TypeVar {
        requirements: Vec<ObjectOption<'a>>,
    },
    Class {
        parent: Option<&'a ObjectOption<'a>>,
    },
    Func {
        type_args: Vec<String>,
        args: Vec<String>,
        return_type: FuncReturnTypeOption,
        name: String,
    },
}

enum VarRegistryTreeConnection<'a> {
    Child { parent: &'a mut VarRegistry<'a> },
    Base { uid_counter: u32 },
}

enum FuncReturnTypeOption {
    TypeArg(u32),
    Static(u32),
}

fn activeate_func_parse<'a>(
    func_term: Term,
    var_registry: &'a mut VarRegistry<'a>,
) -> Result<ActiveParse, ActiveParserError> {
    if let Term::Func {
        name,
        returntype,
        typeargs,
        args,
        block,
    } = func_term
    {
        let mut var_registry = var_registry.create_child();
        for arg in args {
            var_registry.add_var(arg.identity, arg.argtype)
        }

        for typearg in typeargs {
            var_registry.add_typevar(typearg)
        }

        todo!()
    } else {
        Err(ActiveParserError(
            "Expected function term".to_string(),
            FileLocation::None,
        ))
    }
}

fn activate_file_block(file_block: Term) -> Result<ActiveParse, ActiveParserError> {
    let mut var_registry = VarRegistry::new();
    let active_terms = Vec::<ActiveParse>::new();

    if let Term::Block { terms } = file_block {
        for term in terms {
            {
                let out = match term {
                    Term::Func { .. } => activeate_func_parse(term, &mut var_registry),
                    Term::Class { .. } => todo!(),
                    _ => todo!(),
                };
            }
        }
        Ok(ActiveParse::File { active_terms })
    } else {
        Err(ActiveParserError(
            "Expected block as wrapper parse object".to_string(),
            FileLocation::None,
        ))
    }
}

pub fn activate_parse(program: Term) -> Result<ActiveParse, ActiveParserError> {
    activate_file_block(program)
}

The program fails to pass the barrow checker with the following error:

error[E0499]: cannot borrow `var_registry` as mutable more than once at a time
   --> src/avtive_parser/mod.rs:127:69
    |
127 |                     Term::Func { .. } => activeate_func_parse(term, &mut var_registry),
    |                                                                     ^^^^^^^^^^^^^^^^^
    |                                                                     |
    |                                                                     `var_registry` was mutably borrowed here in the previous iteration of the loop
    |                                                                     first borrow used here, in later iteration of loop

I understand the error itself but I cannot find a way to work around this. I need all function calls to create a new child on the base VarRegistry tree.

Is there a way to allow this barrow to safely or an alternative work around?

I have already tried using scopes to stop the borrowing error

fn activate_file_block(file_block: Term) -> Result<ActiveParse, ActiveParserError> {
    let mut var_registry = VarRegistry::new();
    let active_terms = Vec::<ActiveParse>::new();

    if let Term::Block { terms } = file_block {
        for term in terms {
            {
                let mut local_reg = &mut var_registry;
                let out = match term {
                    Term::Func { .. } => activeate_func_parse(term, &mut local_reg),
                    Term::Class { .. } => todo!(),
                    _ => todo!(),
                };
            }
        }
        Ok(ActiveParse::File { active_terms })
    } else {
        Err(ActiveParserError(
            "Expected block as wrapper parse object".to_string(),
            FileLocation::None,
        ))
    }
}

but this code results in two errors:

A new borrowing error

error[E0499]: cannot borrow `var_registry` as mutable more than once at a time
   --> src/avtive_parser/mod.rs:126:37
    |
126 |                 let mut local_reg = &mut var_registry;
    |                                     ^^^^^^^^^^^^^^^^^
    |                                     |
    |                                     `var_registry` was mutably borrowed here in the previous iteration of the loop
    |                                     first borrow used here, in later iteration of loop

And a new lifetime error

error[E0597]: `local_reg` does not live long enough
   --> src/avtive_parser/mod.rs:128:69
    |
126 |                 let mut local_reg = &mut var_registry;
    |                     -------------   ----------------- borrow later used here
    |                     |
    |                     binding `local_reg` declared here
127 |                 let out = match term {
128 |                     Term::Func { .. } => activeate_func_parse(term, &mut local_reg),
    |                                                                     ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
132 |             }
    |             - `local_reg` dropped here while still borrowed

0

There are 0 answers