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

match binding is unexpectedly mutable #12452

Closed
lilyball opened this issue Feb 21, 2014 · 8 comments
Closed

match binding is unexpectedly mutable #12452

lilyball opened this issue Feb 21, 2014 · 8 comments

Comments

@lilyball
Copy link
Contributor

Submitted from reddit. The following code works, and it shouldn't:

enum Foo {
    Bar(int)
}

fn main() {
    let bar = Bar(1);
    match bar {
        Bar(x) => { // shouldn't x be immutable?
            println!("x = {}" ,x);
            x += 1;
            println!("x = {}" ,x);
        }
    }
}

This prints

x = 1
x = 2
@alexcrichton
Copy link
Member

Oh dear, that's bad. Nominating.

@flaper87
Copy link
Contributor

This fails, though:

enum Foo {
    Bar(~[int])
}

fn main() {
    let bar = Bar(~[1,2,3]);
    match bar {
        Bar(x) => {
            println!("x = {}", x.len());
            x.push(4);
            println!("x = {}", x.len());
        }
    }
}

@lilyball
Copy link
Contributor Author

This fails as well:

enum Foo {
    Bar(int)
}

fn main() {
    let bar = Bar(1);
    match bar {
        Bar(x) => { // shouldn't x be immutable?
            println!("x = {}" ,x);
            x += 1;
            x += 2;
            println!("x = {}" ,x);
        }
    }
}

I expect it's using whatever machinery allows let x; x = 3; and mistakenly thinks that x hasn't been assigned yet.

@arjantop
Copy link
Contributor

@flaper87: but any assignment works (e. g.: x = ~[]), all after the first fail (with error x assigned in previous assignment that shouldn't be allowed)

@flaper87
Copy link
Contributor

@arjantop good point, this one doesn't fail

enum Foo {
    Bar(~[int])
}

fn main() {
    let bar = Bar(~[1,2,3]);
    match bar {
        Bar(mut x) => {
            println!("x = {}", x.len());
            x = ~[1];
            println!("x = {}", x.len());
        }
    }
}

@huonw
Copy link
Member

huonw commented Feb 22, 2014

@flaper87 as you've written it, your code is meant to compile (mut x).

But, it also compiles without the mut: it looks like this is an control-flow thing, were the compiler is treating this pattern match the same as:

let x; // don't initialise immediately
// ...
x = 1; // initialise later

because any attempt to borrow it as &mut fails (e.g. the .push failure, and writing &mut x; instead of x = 1; fails).

@edwardw
Copy link
Contributor

edwardw commented Feb 23, 2014

r?

edwardw added a commit to edwardw/rust that referenced this issue Feb 24, 2014
In its first pass, namely gather_loans, the borrow checker tracks the
initialization sites among other things it does. It does so for let
bindings with initializers but not for bindings in match arms, which are
effectively also assignments. This patch does that for borrow checker.

Closes rust-lang#12452.
@flaper87
Copy link
Contributor

@huonw I know it is meant to compile, I was just generating new examples of cases where it works as expected and not.

bors added a commit to rust-lang-ci/rust that referenced this issue Jul 25, 2022
… r=Veykril

feature: `Merge imports` assist can merge multiple selected imports.

The selected imports have to have a common prefix in paths.

Select imports or use trees to merge:
```rust
$0use std::fmt::Display;
use std::fmt::Debug;
use std::fmt::Write;$0
```
Apply `Merge imports`:
```rust
use std::fmt::{Display, Debug, Write};
```

Closes rust-lang#12426
matthiaskrgr pushed a commit to matthiaskrgr/rust that referenced this issue Mar 21, 2024
[`manual_retain`]: Fix duplicate diagnostics

Relates to: rust-lang#12379

The first lint guard executed in `LateLintPass::check_expr` was testing if the parent was of type `ExprKind::Assign`.  This meant the lint emitted on both sides of the assignment operator when `check_expr` is called on either `Expr`.  The guard in the fix only lints once when the `Expr` is of kind `Assign`.

changelog:  Fix duplicate lint diagnostic emission from [`manual_retain`]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants