Skip to content

MIR borrowck: AST error message refers to kind of item that can't be borrowed #46629

Closed

Description

@arielb1

e.g. in E0596:

fn main() {
    let x = 1;
    let y = &mut x; //[ast]~ ERROR [E0596]
                    //[mir]~^ ERROR [E0596]
}

AST borrowck knows that x is an "immutable local variable", but MIR semi-inaccurately calls it an immutable item:

error[E0596]: cannot borrow immutable local variable `x` as mutable (Ast)
  --> /home/ariel/Rust/rust-master/src/test/compile-fail/E0596.rs:16:18
   |
15 |     let x = 1;
   |         - consider changing this to `mut x`
16 |     let y = &mut x; //[ast]~ ERROR [E0596]
   |                  ^ cannot borrow mutably

error[E0596]: cannot borrow immutable item `x` as mutable (Mir)
  --> /home/ariel/Rust/rust-master/src/test/compile-fail/E0596.rs:16:13
   |
16 |     let y = &mut x; //[ast]~ ERROR [E0596]
   |             ^^^^^^ cannot borrow as mutable

error: aborting due to 2 previous errors

The AST code for doing that is actually in mem_categorization, and should be ported to MIR borrowck:

pub fn descriptive_string(&self, tcx: TyCtxt) -> String {

Activity

  1. arielb1 commented on Dec 10, 2017

    @arielb1
    ContributorAuthor

    I think the mc code sometimes generates ugly error messages - it should be called on the lvalue that causes the mutability error, not on the full lvalue - but you can use it as a reference to improve the errors.

  2. arielb1 commented on Dec 10, 2017

    @arielb1
    ContributorAuthor

    Note: if you do this correctly, you should also be able to reroute closure errors into things like E0387 - "cannot assign to data in a captured outer variable in an Fn closure" instead of the standard "cannot borrow immutable item as mutable". See e.g. the borrow-immutable-upvar-mutation test:

    // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
    // file at the top-level directory of this distribution and at
    // http://rust-lang.org/COPYRIGHT.
    //
    // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
    // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
    // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
    // option. This file may not be copied, modified, or distributed
    // except according to those terms.
    
    #![feature(unboxed_closures)]
    
    // Tests that we can't assign to or mutably borrow upvars from `Fn`
    // closures (issue #17780)
    
    fn set(x: &mut usize) { *x = 5; }
    
    fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
    fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
    
    fn main() {
        // By-ref captures
        {
            let mut x = 0;
            let _f = to_fn(|| x = 42); //~ ERROR cannot assign
    
            let mut y = 0;
            let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
    
            let mut z = 0;
            let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign
        }
    
        // By-value captures
        {
            let mut x = 0;
            let _f = to_fn(move || x = 42); //~ ERROR cannot assign
    
            let mut y = 0;
            let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
    
            let mut z = 0;
            let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
        }
    }
  3. arielb1 commented on Dec 10, 2017

    @arielb1
    ContributorAuthor

    In that case, the error message we emit is especially terrible, because it is not obvious that the problem is with the closure:

    error[E0594]: cannot assign to immutable item `x` (Mir)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:25:27
       |
    25 |         let _f = to_fn(|| x = 42); //~ ERROR cannot assign
       |                           ^^^^^^ cannot mutate
    
    error[E0596]: cannot borrow immutable item `y` as mutable (Mir)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:28:31
       |
    28 |         let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
       |                               ^^^^^^ cannot borrow as mutable
    
    error[E0594]: cannot assign to immutable item `x` (Mir)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:37:32
       |
    37 |         let _f = to_fn(move || x = 42); //~ ERROR cannot assign
       |                                ^^^^^^ cannot mutate
    
    error[E0596]: cannot borrow immutable item `y` as mutable (Mir)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:40:36
       |
    40 |         let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
       |                                    ^^^^^^ cannot borrow as mutable
    
    error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure (Ast)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:25:27
       |
    25 |         let _f = to_fn(|| x = 42); //~ ERROR cannot assign
       |                           ^^^^^^
       |
    help: consider changing this closure to take self by mutable reference
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:25:24
       |
    25 |         let _f = to_fn(|| x = 42); //~ ERROR cannot assign
       |                        ^^^^^^^^^
    
    error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure (Ast)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:28:36
       |
    28 |         let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
       |                                    ^
       |
    help: consider changing this closure to take self by mutable reference
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:28:24
       |
    28 |         let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
       |                        ^^^^^^^^^^^^^^
    
    error[E0387]: cannot assign to data in a captured outer variable in an `Fn` closure (Ast)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:31:55
       |
    31 |         let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign
       |                                                       ^^^^^^
       |
    help: consider changing this closure to take self by mutable reference
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:31:52
       |
    31 |         let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign
       |                                                    ^^^^^^^^^
    
    error[E0594]: cannot assign to captured outer variable in an `Fn` closure (Ast)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:37:32
       |
    36 |         let mut x = 0;
       |             ----- help: consider making `mut x` mutable: `mut mut x`
    37 |         let _f = to_fn(move || x = 42); //~ ERROR cannot assign
       |                                ^^^^^^
       |
    help: consider changing this closure to take self by mutable reference
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:37:24
       |
    37 |         let _f = to_fn(move || x = 42); //~ ERROR cannot assign
       |                        ^^^^^^^^^^^^^^
    
    error[E0596]: cannot borrow captured outer variable in an `Fn` closure as mutable (Ast)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:40:41
       |
    40 |         let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
       |                                         ^
       |
    help: consider changing this closure to take self by mutable reference
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:40:24
       |
    40 |         let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
       |                        ^^^^^^^^^^^^^^^^^^^
    
    error[E0594]: cannot assign to captured outer variable in an `Fn` closure (Ast)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:43:65
       |
    42 |         let mut z = 0;
       |             ----- help: consider making `mut z` mutable: `mut mut z`
    43 |         let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
       |                                                                 ^^^^^^
       |
    help: consider changing this closure to take self by mutable reference
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:43:57
       |
    43 |         let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
       |                                                         ^^^^^^^^^^^^^^
    
    warning: variable does not need to be mutable
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:36:13
       |
    36 |         let mut x = 0;
       |             ---^^
       |             |
       |             help: remove this `mut`
       |
       = note: #[warn(unused_mut)] on by default
    
    warning: variable does not need to be mutable
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:39:13
       |
    39 |         let mut y = 0;
       |             ---^^
       |             |
       |             help: remove this `mut`
    
    error[E0594]: cannot assign to immutable item `z` (Mir)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:31:55
       |
    31 |         let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign
       |                                                       ^^^^^^ cannot mutate
    
    error[E0594]: cannot assign to immutable item `z` (Mir)
      --> /home/ariel/Rust/rust-master/src/test/compile-fail/borrow-immutable-upvar-mutation.rs:43:65
       |
    43 |         let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
       |                                                                 ^^^^^^ cannot mutate
    
    error: aborting due to 12 previous errors
    
  4. added
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    on Mar 26, 2018
  5. nikomatsakis commented on Apr 3, 2018

    @nikomatsakis
    Contributor

    Semi-dup of #47388

  6. nikomatsakis commented on Jul 3, 2018

    @nikomatsakis
    Contributor

    It seems like we still say things like "immutable item". This doesn't seem great. Tagging for release candidate.

  7. nikomatsakis commented on Jul 3, 2018

    @nikomatsakis
    Contributor
    athena. rustc +nightly E0596.rs -Zborrowck=mir
    warning: unused variable: `y`
      --> E0596.rs:16:9
       |
    16 |     let y = &mut x; //[ast]~ ERROR [E0596]
       |         ^ help: consider using `_y` instead
       |
       = note: #[warn(unused_variables)] on by default
    
    error[E0596]: cannot borrow immutable item `x` as mutable
      --> E0596.rs:16:13
       |
    15 |     let x = 1;
       |         - help: consider changing this to be mutable: `mut x`
    16 |     let y = &mut x; //[ast]~ ERROR [E0596]
       |             ^^^^^^ cannot borrow as mutable
    
    error: aborting due to previous error
    
  8. nikomatsakis commented on Jul 3, 2018

    @nikomatsakis
    Contributor

    Honestly, I think I would prefer to see this phrased rather differently. Something like:

    "cannot borrow x mutably, as it is not declared as mutable"

  9. self-assigned this
    on Jul 9, 2018
  10. added a commit that references this issue on Jul 21, 2018
    942b384
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-NLLArea: Non-lexical lifetimes (NLL)A-borrow-checkerArea: The borrow checkerA-diagnosticsArea: Messages for errors, warnings, and lintsC-enhancementCategory: An issue proposing an enhancement or a PR with one.NLL-diagnosticsWorking towards the "diagnostic parity" goal

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions