Skip to content

regression: rustc suggests .as_ref() at incorrect location and other spans have regressed #90286

Description

@camelid

Code

Playground (regressed rustc version)

fn foo(opt: &Option<Box<i32>>) -> String {
    opt.map(|x| x.to_string()).unwrap_or_else(String::new)
}

Output (stable 1.56.0, good)

error[E0507]: cannot move out of `*opt` which is behind a shared reference
 --> src/lib.rs:2:5
  |
2 |     opt.map(|x| x.to_string()).unwrap_or_else(String::new)
  |     ^^^ move occurs because `*opt` has type `Option<Box<i32>>`, which does not implement the `Copy` trait
  |
help: consider borrowing the `Option`'s content
  |
2 |     opt.as_ref().map(|x| x.to_string()).unwrap_or_else(String::new)
  |        +++++++++

For more information about this error, try `rustc --explain E0507`.

Output (beta 1.57.0-beta.2, incorrect)

error[E0507]: cannot move out of `*opt` which is behind a shared reference
 --> src/lib.rs:2:5
  |
2 |     opt.map(|x| x.to_string()).unwrap_or_else(String::new)
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `*opt` has type `Option<Box<i32>>`, which does not implement the `Copy` trait
  |
help: consider borrowing the `Option`'s content
  |
2 |     opt.map(|x| x.to_string()).as_ref().unwrap_or_else(String::new)
  |                               +++++++++

For more information about this error, try `rustc --explain E0507`.

Activity

  1. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    C-bugCategory: This is a bug.
    A-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`
    D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.
    D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.
    on Oct 25, 2021
  2. added this to the 1.57.0 milestone on Oct 25, 2021
  3. added
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Oct 25, 2021
  4. added
    E-needs-bisectionCall for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc
    on Oct 25, 2021
  5. camelid commented on Oct 25, 2021

    @camelid
    MemberAuthor

    My hunch is that this regression is caused by the change in error spans between stable and beta, which also feels like a regression to me since it makes the span less specific:

    stable:

    2 |     opt.map(|x| x.to_string()).unwrap_or_else(String::new)
      |     ^^^ move occurs because `*opt` has type `Option<Box<i32>>`, which does not implement the `Copy` trait
    

    beta:

    2 |     opt.map(|x| x.to_string()).unwrap_or_else(String::new)
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `*opt` has type `Option<Box<i32>>`, which does not implement the `Copy` trait
    
  6. WaffleLapkin commented on Oct 26, 2021

    @WaffleLapkin
    Member

    searched nightlies: from nightly-2021-09-29 to nightly-2021-10-21
    regressed nightly: nightly-2021-10-01
    searched commit range: 1149193...aa7aca3
    regressed commit: 4aa7879

    bisected with cargo-bisect-rustc v0.6.1

    Host triple: x86_64-unknown-linux-gnu
    Reproduce with:

    cargo bisect-rustc --preserve --test-dir=tstdr --end=2021-10-21 --script=./test.sh

    test.sh:

    #!/bin/sh
    
    cargo check 2>&1 | grep " ^^^ move occurs because"
  7. camelid commented on Oct 26, 2021

    @camelid
    MemberAuthor

    cc @Aaron1011 @estebank

    The new spans caused this suggestion regression, and I feel like they make the errors harder to read in some cases.

  8. Aaron1011 commented on Oct 26, 2021

    @Aaron1011
    Contributor

    @camelid: Setting aside the incorrect suggestion for the moment, I think the new span is better. By itself, pointing to opt does not explain why a move is occuring, as not every usage of a variable name is a move. Pointing to the the method call helps emphasize that the method call is responsible for the move.

    However, I think adding a note could help emphasize that the method is causing the move (we already do this for other borrowcheck errors).

    The incorrect suggestion is tricky - I'll see if I can do something about that.

  9. camelid commented on Oct 26, 2021

    @camelid
    MemberAuthor

    Setting aside the incorrect suggestion for the moment, I think the new span is better. By itself, pointing to opt does not explain why a move is occuring, as not every usage of a variable name is a move. Pointing to the the method call helps emphasize that the method call is responsible for the move.

    I understand, and I can see how highlighting the whole call is more correct in some ways, but then a lot of code is highlighted, which can be visually distracting. I wonder if it could make sense to highlight just the method name?

    opt.map(|x| x.to_string())
    ^^^^^^^
    

    Although that looks a bit weird. Another option is something like this:

    opt.map(|x| x.to_string())
    ^^^ --- `opt` moved by `map` here
    

    Additionally, a large part of why I feel the new span is visually distracting is that move occurs because `*opt` has type `Option<Box<i32>>`, which does not implement the `Copy` trait takes up a lot of space as a span_label with the new span. Perhaps the new span could be made easier to read if the label were moved to a note?

  10. 19 remaining items

  11. added
    regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.
    and removed on Dec 2, 2021
  12. fogti commented on Dec 10, 2021

    @fogti
    Contributor

    Could, as a temporary somewhat-partial mitigation, the as_ref suggestion be downgraded from {points directly at a (currently wrong) location in the code} to {it is suggested in a note that an as_ref should be inserted near the highlighted code, but without a direct pointer with +++}?. That would reduce the confusion a bit, I suppose.

  13. estebank commented on Aug 19, 2022

    @estebank
    Contributor

    Triage: fixed in current beta:

    error[E0507]: cannot move out of `*opt` which is behind a shared reference
     --> src/lib.rs:2:5
      |
    2 |     opt.map(|x| x.to_string()).unwrap_or_else(String::new)
      |     ^^^^----------------------
      |     |   |
      |     |   `*opt` moved due to this method call
      |     move occurs because `*opt` has type `Option<Box<i32>>`, which does not implement the `Copy` trait
      |
    note: this function takes ownership of the receiver `self`, which moves `*opt`
    help: consider calling `.as_ref()` to borrow the type's contents
      |
    2 |     opt.as_ref().map(|x| x.to_string()).unwrap_or_else(String::new)
      |         +++++++++
    
  14. added
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    and removed
    P-highHigh priority
    regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.
    C-bugCategory: This is a bug.
    on Aug 19, 2022
  15. added 2 commits that reference this issue on Aug 20, 2022
  16. WaffleLapkin commented on Aug 22, 2022

    @WaffleLapkin
    Member

    Hm, it seems like there are already tests for as_ref suggestion, namely option-content-move.rs, as-ref.rs and as-ref-2.rs, should this be closed then?

  17. fogti commented on Aug 23, 2022

    @fogti
    Contributor

    should we wait for the commits which seem to fix this to hit stable, or can we close this already?

  18. estebank commented on Aug 23, 2022

    @estebank
    Contributor

    We can close now.

  19. added a commit that references this issue on Jul 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions