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

Adding type annotation equivalent to existing type changes code semantics #35919

Open
F001 opened this issue Aug 23, 2016 · 7 comments
Open

Adding type annotation equivalent to existing type changes code semantics #35919

F001 opened this issue Aug 23, 2016 · 7 comments
Labels
A-type-system Area: Type system C-enhancement Category: An issue proposing an enhancement or a PR with one. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@F001
Copy link
Contributor

F001 commented Aug 23, 2016

This piece of code can't compile:

fn main()
{
    let y = &mut 2i32;
    {
        let x = y;
        *x = 3;
    }
    println!("{}", y);
}

But, if we add the type annotation, it compiles:

fn main()
{
    let y = &mut 2i32;
    {
        let x: &mut i32 = y;
        *x = 3;
    }
    println!("{}", y);
}

I guess the later form triggers "auto-deref" mechanism, which equals to:

let x = &mut *y;

But this behaviour is still very confusing. Type annotation or not doesn't change the type of x at all. Type of x is always &mut i32. But they lead to different compile result. I have no idea whether should we fix it.

@jonas-schievink
Copy link
Contributor

I don't think autoderef is involved here, the type of x still seems to be inferred to &mut i32. Looks like some weird interaction with reborrows (a reborrow is occurring in the second case but not the first).

@jonas-schievink
Copy link
Contributor

Looks like a duplicate of #25899, but I think we should keep it open anyways since this is very confusing

@Mark-Simulacrum Mark-Simulacrum added the A-diagnostics Area: Messages for errors, warnings, and lints label May 12, 2017
@Mark-Simulacrum Mark-Simulacrum changed the title confusing type annotation Adding type annotation equivalent to existing type changes code semantics May 12, 2017
@Mark-Simulacrum Mark-Simulacrum removed the A-diagnostics Area: Messages for errors, warnings, and lints label May 12, 2017
@Mark-Simulacrum
Copy link
Member

Well, actually, this isn't really a diagnostics issue--I'm going to nominate for a lang team discussion so that we can see what we want to do here, and can we do anything here. For reference the first example compiles with the following error today:

error[E0382]: use of moved value: `y`
 --> test.rs:8:20
  |
5 |         let x = y;
  |             - value moved here
...
8 |     println!("{}", y);
  |                    ^ value used here after move
  |
  = note: move occurs because `y` has type `&mut i32`, which does not implement the `Copy` trait

error: aborting due to previous error

@Mark-Simulacrum Mark-Simulacrum added I-nominated T-lang Relevant to the language team, which will review and decide on the PR/issue. labels May 12, 2017
@nikomatsakis
Copy link
Contributor

The reason that this happens is that, in the second case, where the expected type is known, we will do a "reborrow coercion" (in particular, when coercing from &mut to &mut). This means that the variable is not considered "moved". In the first case, though, the target type is not known, and hence we consider it a move. This is suboptimal but not wrong (in general, annotating let can induce coercions and have other changes).

I think we could fix this (potentially) by detecting the case that we are coercing an &mut to an unknown type and pre-emptively inserting a &mut * reborrow. I think this can only make errors go away, and not cause them. Probably worth trying anyway. I'd be up to mentor this.

@nikomatsakis nikomatsakis added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-type-system Area: Type system E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. C-enhancement Category: An issue proposing an enhancement or a PR with one. and removed T-lang Relevant to the language team, which will review and decide on the PR/issue. labels May 25, 2017
@nikomatsakis
Copy link
Contributor

Don't have time to write up detailed stuff. The basic idea is to look into the src/librustc_typeck/check/coercion.rs.

@F001
Copy link
Contributor Author

F001 commented May 10, 2018

Thanks for the information. It is helpful.

I tried to fix this problem, but failed. Because "always re-borrow" is not a good strategy for the time being. libstd/io/mod.rs can not compile after this change. The case is simplified as below:

let mut buf : &mut [u8] = init();
{
  let tmp = buf;  // If we automatically add re-borrow here, below line will be failed to compile
  buf = &mut tmp[n..];
}
// Error Message:
// error[E0499]: cannot borrow `*buf` as mutable more than once at a time

I guess it could be solved when NLL is ready. Test case as below:

#![feature(nll)]  // enable nll feature, and the compile error is gone
fn main()
{
    let mut buf : &mut [u8] = &mut [1,2,3];
    {
        let tmp : &mut [u8] = &mut *buf; // enforce re-borrow occurs
        buf = &mut tmp[1..];
    }
    println!("{:?}", buf);
}

I'll try to revisit this issue again after NLL become the default.

@steveklabnik
Copy link
Member

Triage: this still errors today:

   Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `y`
 --> src/main.rs:8:20
  |
3 |     let y = &mut 2i32;
  |         - move occurs because `y` has type `&mut i32`, which does not implement the `Copy` trait
4 |     {
5 |         let x = y;
  |                 - value moved here
...
8 |     println!("{}", y);
  |                    ^ value borrowed here after move

error: aborting due to previous error

@fmease fmease added A-type-system Area: Type system T-types Relevant to the types team, which will review and decide on the PR/issue. and removed A-type-system Area: Type system labels Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system C-enhancement Category: An issue proposing an enhancement or a PR with one. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants