Borrow checker error: borrow occurs due to deref coercion

⚓ rust    📅 2025-06-10    👤 surdeus    👁️ 2      

surdeus

Hi, I am facing borrow checker errors when mutating a vector consisting of borrowed FstNode<'a>s. Here is a shorter version of the code (playground link):

// Uses the `fst` crate. `fst = "0.4.7"`
use std::collections::{HashMap, HashSet};
use fst::raw::{Builder, Fst, Node};

pub struct FstTree {
    fst: Fst<Vec<u8>>,
}

impl FstTree {
    pub fn new(mut set: Vec<&str>) -> Self {
        todo!()
    }

    pub fn match_longest_common_prefix<'a>(&self, prefix: &'a str) -> (&'a str, &'a str, bool) {
        todo!()
    }

    pub fn matching_node<'a>(&'a self, word: &'a str) -> Option<FstNode<'a>> {
        todo!()
    }
}

pub struct FstNode<'a> {
    fst: &'a Fst<Vec<u8>>,
    node: Node<'a>,
    word: String,
}

impl FstNode<'_> {
    pub fn get_matching_node(&self, suffix: &str) -> Option<FstNode<'_>> {
        todo!()
    }

    pub fn get_word(&self) -> Option<&str> {
        todo!()
    }
}

pub struct Block {
    pub transliterate: Vec<String>,
    pub entire_block_optional: Option<bool>,
}

pub struct Suggest {
    patterns: HashMap<String, Block>,
    patterns_trie: FstTree,
    words: FstTree,
    common_suffixes: Vec<String>,
}

impl Suggest {
    pub fn new() -> Self {
        let patterns: HashMap<String, Block> = todo!();
        let patterns_trie: FstTree = todo!();
        let words: FstTree = todo!();
        let common_suffixes = todo!();

        Suggest {
            patterns,
            patterns_trie,
            words,
            common_suffixes,
        }
    }

    pub fn suggest(&self, input: &str) -> Vec<String> {
        let (matched, mut remaining, _) = self.patterns_trie.match_longest_common_prefix(&input);

        let matched_patterns = &self.patterns.get(matched).unwrap().transliterate;
        let mut matched_nodes = matched_patterns
            .iter()
            .filter_map(|p| self.words.matching_node(p))
            .collect::<Vec<_>>();

        let additional_nodes = matched_nodes
            .iter()
            .flat_map(|node| {
                self.common_suffixes
                    .iter()
                    .filter_map(|suffix| node.get_matching_node(suffix))
            })
            .collect::<Vec<_>>();
        matched_nodes.extend(additional_nodes);

        while !remaining.is_empty() {
            let (mut new_matched, mut new_remaining, mut complete) =
                self.patterns_trie.match_longest_common_prefix(&remaining);

            if !complete {
                for i in (0..remaining.len()).rev() {
                    (new_matched, new_remaining, complete) = self
                        .patterns_trie
                        .match_longest_common_prefix(&remaining[..i]);

                    if complete {
                        remaining = &remaining[i..];
                        break;
                    }
                }
            } else {
                remaining = new_remaining;
            }

            let new_matched_patterns = &self.patterns.get(new_matched).unwrap().transliterate;
            let new_matched_nodes = new_matched_patterns
                .iter()
                .flat_map(|p| {
                    matched_nodes
                        .iter()
                        .filter_map(|node| node.get_matching_node(p))
                })
                .collect::<Vec<_>>();

            if self
                .patterns
                .get(new_matched)
                .unwrap()
                .entire_block_optional
                .is_some()
            {
                // Entirely optional patterns like "([ওোঅ]|(অ্য)|(য়ো?))?" may not yield any result
                matched_nodes.extend(new_matched_nodes);
            } else {
                matched_nodes = new_matched_nodes;
            }

            let additional_matched_nodes = matched_nodes
                .iter()
                .flat_map(|node| {
                    self.common_suffixes
                        .iter()
                        .filter_map(|suffix| node.get_matching_node(suffix))
                })
                .collect::<Vec<_>>();
            matched_nodes.extend(additional_matched_nodes);
        }

        let suggestions: HashSet<_> = matched_nodes.iter().filter_map(|n| n.get_word()).collect();
        suggestions.into_iter().map(|s| s.to_string()).collect()
    }
}

The issue seems that the borrow of FstNode<'a> is being spilled out. Here is the borrow checker error:

error[E0502]: cannot borrow `matched_nodes` as mutable because it is also borrowed as immutable
  --> src/lib.rs:82:9
   |
74 |         let additional_nodes = matched_nodes
   |                                ------------- immutable borrow occurs here
...
82 |         matched_nodes.extend(additional_nodes);
   |         ^^^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^
   |         |             |
   |         |             immutable borrow later used by call
   |         mutable borrow occurs here

error[E0502]: cannot borrow `matched_nodes` as mutable because it is also borrowed as immutable
   --> src/lib.rs:121:17
    |
74  |         let additional_nodes = matched_nodes
    |                                ------------- immutable borrow occurs here
...
121 |                 matched_nodes.extend(new_matched_nodes);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
126 |             let additional_matched_nodes = matched_nodes
    |                                            ------------- immutable borrow later used here

error[E0506]: cannot assign to `matched_nodes` because it is borrowed
    --> src/lib.rs:123:17
     |
74   |         let additional_nodes = matched_nodes
     |                                ------------- `matched_nodes` is borrowed here
...
123  |                 matched_nodes = new_matched_nodes;
     |                 ^^^^^^^^^^^^^
     |                 |
     |                 `matched_nodes` is assigned to here but it was already borrowed
     |                 borrow later used here
     |
     = note: borrow occurs due to deref coercion to `[FstNode<'_>]`
note: deref defined here
    --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:3287:5
     |
3287 |     type Target = [T];
     |     ^^^^^^^^^^^

error[E0502]: cannot borrow `matched_nodes` as mutable because it is also borrowed as immutable
   --> src/lib.rs:134:13
    |
74  |         let additional_nodes = matched_nodes
    |                                ------------- immutable borrow occurs here
...
134 |             matched_nodes.extend(additional_matched_nodes);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
137 |         let suggestions: HashSet<_> = matched_nodes.iter().filter_map(|n| n.get_word()).collect();
    |                                       ------------- immutable borrow later used here

I think the important part is:

= note: borrow occurs due to deref coercion to `[FstNode<'_>]`
note: deref defined here
    --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:3287:5
     |
3287 |     type Target = [T];
     |     ^^^^^^^^^^^

How can I fix this issue or there any workarounds available?

Thanks in advance! :heart:

4 posts - 2 participants

Read full topic

🏷️ rust_feed