Omega500
Omega500

Reputation: 97

Cannot borrow `*self` as mutable more than once at a time

The Error

error[E0499]: cannot borrow `*self` as mutable more than once at a time
   --> src\scanner\mod.rs:103:17
    |
45  | impl<'a> Scanner<'a> {
    |      -- lifetime `'a` defined here
...
102 |                 let message = self.intern_str(&message);
    |                               -------------------------
    |                               |
    |                               first mutable borrow occurs here
    |                               argument requires that `*self` is borrowed for `'a`
103 |                 self.error_token(message);
    |                 ^^^^ second mutable borrow occurs here

The code


pub struct ScannerResult<'a> {
    line_starts: &'a mut Vec<usize>,
    tokens: &'a mut Vec<Token<'a>>,
}

impl<'a> ScannerResult<'a> {
    pub fn new(line_starts: &'a mut Vec<usize>, tokens: &'a mut Vec<Token<'a>>) -> Self {
        Self {
            line_starts,
            tokens,
        }
    }

    pub fn push_token(&mut self, token: Token<'a>) {
        self.tokens.push(token);
    }

    pub fn push_line_start(&mut self, line_start: usize) {
        self.line_starts.push(line_start);
    }
}
struct Scanner<'a> {
    src: Chars<'a>,
    offset: usize,
    start: usize,
    size: usize,
    string_table: &'a mut HashSet<String>,
    keyword_trie: KeywordTrie,
    result: &'a mut ScannerResult<'a>,
    has_more_tokens: bool,
}

impl<'a> Scanner<'a> {
    pub fn new(
        src: &'a str,
        size: usize,
        string_table: &'a mut HashSet<String>,
        result: &'a mut ScannerResult<'a>,
    ) -> Self {
        Self {
            src: src.chars(),
            offset: 0,
            start: 0,
            size,
            string_table,
            keyword_trie: KeywordTrie::new(),
            result,
            has_more_tokens: true,
        }
    }

    fn next(&'a mut self) -> Option<&Token<'a>> {
        self.skipWhitespaces();
        if self.is_eof() {
            return self.tokenize_eof();
        }

        let c = self.advance();

        if c.is_none() {
            return None;
        }

        let c = c.unwrap();

        return match c {
            '{' => self.tokenize(&TokenType::OPEN_CURLY_BRACKET, None),
            '}' => self.tokenize(&TokenType::CLOSE_CURLY_BRACKET, None),
            '(' => self.tokenize(&TokenType::OPEN_PAREN, None),
            ')' => self.tokenize(&TokenType::CLOSE_PAREN, None),
            '[' => self.tokenize(&TokenType::OPEN_SQUARE_BRACKET, None),
            ']' => self.tokenize(&TokenType::CLOSE_SQUARE_BRACKET, None),
            ':' => self.tokenize(&TokenType::COLON, None),
            ';' => self.tokenize(&TokenType::SEMICOLON, None),
            ',' => self.tokenize(&TokenType::COMMA, None),
            '@' => self.tokenize(&TokenType::AT, None),
            _ => {
                let message = format!("Unexpected character: {}", c);
                let message = self.intern_str(&message);
                self.error_token(message);
                return None;
            }
        };
    }

    fn error_token(&mut self, message: &'a str) -> Option<&Token<'a>> {
        return self.tokenize(&TokenType::ERROR, Some(message));
    }

    fn tokenize_eof(&mut self) -> Option<&Token<'a>> {
        self.has_more_tokens = false;
        self.tokenize(&TokenType::EOF, None)
    }

    fn intern_str(&mut self, string: &String) -> &str {
        if !self.string_table.contains(string) {
            self.string_table.insert(string.to_owned());
        }
        self.string_table.get(string).unwrap()
    }

    fn tokenize(
        &mut self,
        token_type: &'static TokenType,
        lexeme: Option<&'a str>,
    ) -> Option<&Token<'a>> {
        let token: Token<'a> = Token::new(token_type, lexeme, self.start, self.offset);
        self.result.push_token(token);
        self.start = self.offset;
        self.result.tokens.last()
    }
}

I somewhat understand why this might be happening but i got no solution in hand. I tried making it inline, borrow string_table rather than self, without interning i get the "message" doesn't live long enough error, can't make it 'static because it use char to show the unexpected character.

New to rust currently fighting the borrow checker. Need help.

Upvotes: 0

Views: 42

Answers (0)

Related Questions