Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Borrow checker reports multiple mutable borrows when there's only one #9068

Closed
catamorphism opened this issue Sep 9, 2013 · 6 comments
Closed
Labels
A-lifetimes Area: Lifetimes / regions

Comments

@catamorphism
Copy link
Contributor

Perhaps I'm going about it wrong, but I would hope that the following code would compile:

#[deriving(Clone, Eq, Encodable, Decodable)]
struct WorkMap(TreeMap<~str, KindMap>);

#[deriving(Clone, Eq, Encodable, Decodable)]
struct KindMap(TreeMap<~str, ~str>);

impl WorkMap {
    fn new() -> WorkMap { WorkMap(TreeMap::new()) }

    fn insert_work_key(&mut self, k: WorkKey, val: ~str) {
        let WorkKey { kind, name } = k;
        match self.find_mut(&name) {
            Some(&KindMap(ref mut m)) => { m.insert(kind, val); },
            None => {
                let mut new_map = TreeMap::new();
                new_map.insert(kind, val);
                self.insert(name, KindMap(new_map));
            }
        }
    }
}

The error message:

/Users/tjc/rust/src/libextra/workcache.rs:126:16: 126:21 error: cannot borrow `(*self)#0` as mutable more than once at a time
/Users/tjc/rust/src/libextra/workcache.rs:126                 self.insert(name, KindMap(new_map));
                                                              ^~~~~
/Users/tjc/rust/src/libextra/workcache.rs:121:14: 121:19 note: second borrow of `(*self)#0` as mutable occurs here
/Users/tjc/rust/src/libextra/workcache.rs:121         match self.find_mut(&name) {
                                                            ^~~~~

It would be nice if the borrow checker knew that in the None branch, there was no longer a reference to self arising from the call to find_mut, so at the call to insert, there are no other mutable borrows of self. Naively, I'd think this would fall under flow-sensitivity, but maybe not?

/cc @nikomatsakis

@alexcrichton
Copy link
Member

I thought I'd seen an issue for this so far, it forget where it went though. I also have this pattern a fair amount, and it's be awesome to be able to work. The workaround I've always used is to have a break/return in the Some case and then have the None case fall out of the match to perform the insert, but that can't always happen sadly :(

@metajack
Copy link
Contributor

metajack commented Sep 9, 2013

I think this is a case of TreeMap missing methods that HashMap has. I was sure I filed a similar bug a long time ago, and found this, which was fixed (on HashMap):
#6394

There is also #6393 which I filed around the same time.

@nikomatsakis
Copy link
Contributor

Def a dup of #6393. I propose either closing the bug or repurposing it to be a request for find_or_insert_with and friends to be added to TreeMap (if they are indeed missing).

@cadencemarseille
Copy link
Contributor

I ran into this issue with:

let mut table: TreeMap<~str, ~[int]> = TreeMap::new();
let key = ~"test1";

match table.find_mut(&key) {
    None    => table.insert(key.clone(), ~[1]),
    Some(v) => { v.push(1); false }
};

Workaround:

if !table.contains_key(&key) {
    table.insert(key, ~[1]);
} else {
    table.find_mut(&key).unwrap().push(1);
}

@ezyang
Copy link
Contributor

ezyang commented Dec 18, 2013

find_or_insert_with and friends are not in treemap. I spent a little time trying to implement them, but I wasn't sure what the best way to structure the code was. hashmap has its 'mangle' function which implements all of the functionality all of the other operations could possibly need, which would work for 'treemap', but I kind of wonder if hashmap is paying a performance cost for having such a general function.

@steveklabnik
Copy link
Member

Triage: this bug is very old, and so I'm not sure it's really actionable. As the above comments state, it's a dup of #6393, and possibly with a mixture of collection methods that no longer exist. Therefore, I'm giving it a close.

flip1995 pushed a commit to flip1995/rust that referenced this issue Jun 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions
Projects
None yet
Development

No branches or pull requests

7 participants