Skip to content

format! .into() suggestion deletes the format macro #110017

Closed

Description

@ehuss

Code

pub fn foo(x: &str) -> Result<(), Box<dyn std::error::Error>> {
    Err(format!("error: {x}"))
}

Current output

Checking foo v0.1.0 (/Users/eric/Temp/foo)
error[E0308]: mismatched types
 --> src/lib.rs:2:9
  |
2 |     Err(format!("error: {x}"))
  |         ^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String`
  |
  = note: expected struct `Box<dyn std::error::Error>`
             found struct `String`
  = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
 --> /Users/eric/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/macros.rs:121:12
  |
12|         res.into()
  |            +++++++

For more information about this error, try `rustc --explain E0308`.
error: could not compile `foo` (lib) due to previous error

Desired output

Checking foo v0.1.0 (/Users/eric/Temp/foo)
error[E0308]: mismatched types
 --> src/lib.rs:2:9
  |
2 |     Err(format!("error: {x}"))
  |         ^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Error>`, found `String`
  |
  = note: expected struct `Box<dyn std::error::Error>`
             found struct `String`
  = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
 --> /Users/eric/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/macros.rs:121:12
  |
12|          Err(format!("error: {x}").into())
  |                                   +++++++

For more information about this error, try `rustc --explain E0308`.
error: could not compile `foo` (lib) due to previous error

Rationale and extra context

The suggestion converts the code to:

Err(.into())

which is invalid.

It should suggest:

Err(format!("error: {x}").into())

The suggestion works correctly for non-macro string values.

This suggestion was introduced in #102496.

Other cases

No response

Anything else?

rustc 1.70.0-nightly (cf7ada217 2023-04-03)
binary: rustc
commit-hash: cf7ada217c8ac63367b184afd9fffaff30f6ed44
commit-date: 2023-04-03
host: aarch64-apple-darwin
release: 1.70.0-nightly
LLVM version: 16.0.0

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.
    D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.
    on Apr 6, 2023
  2. mu001999 commented on Apr 7, 2023

    @mu001999
    Member

    It cannot be reproduced on play.

  3. Ezrashaw commented on Apr 7, 2023

    @Ezrashaw
    Contributor

    I'm able to reproduce it locally. It seems to be suggesting a change in libstd:

    help: call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`
     --> /Users/eric/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/macros.rs:121:12
    

    (note the path)

    I assume that this is due to macro expansion. It might not be working on the playground because the playground doesn't have the rust-src component installed but that's a total guess.

  4. ehuss commented on Apr 7, 2023

    @ehuss
    ContributorAuthor

    The presence of rust-src only affects the human-readable rendering. The important part to me is the JSON output which has "suggested_replacement": ".into()" even without rust-src.

    Ideally it would be something closer to what it looks like with Err(String::new()):

        {
          "children": [],
          "code": null,
          "level": "help",
          "message": "call `Into::into` on this expression to convert `String` into `Box<dyn std::error::Error>`",
          "rendered": null,
          "spans": [
            {
              "byte_end": 85,
              "byte_start": 85,
              "column_end": 22,
              "column_start": 22,
              "expansion": null,
              "file_name": "src/lib.rs",
              "is_primary": true,
              "label": null,
              "line_end": 2,
              "line_start": 2,
              "suggested_replacement": ".into()",
              "suggestion_applicability": "MaybeIncorrect",
              "text": [
                {
                  "highlight_end": 22,
                  "highlight_start": 22,
                  "text": "    Err(String::new())"
                }
              ]
            }
          ]
        }
  5. mu001999 commented on Apr 7, 2023

    @mu001999
    Member

    It seems to affect all macro expansions (play):

    macro_rules! s {
        ($e: expr) => {
            String::from($e)
        }
    }
    
    pub fn foo(x: &str) -> Result<(), Box<dyn std::error::Error>> {
        Err(s!(x))
    }
  6. Ezrashaw commented on Apr 7, 2023

    @Ezrashaw
    Contributor

    Is the solution to just disable this suggestion for macro-expanded code?

    As an aside, perhaps the playground should get rust-src, especially because of its prevalence in sharing code which might need the additional context.

  7. fmease commented on Apr 7, 2023

    @fmease
    Member

    Is the solution to just disable this suggestion for macro-expanded code?

    I think it's possible to achieve the desired output found in the description, although I'm not sure how exactly.
    Typically, you would use find_ancestor_inside on the span to peel away the layers of macro invocations, though for
    that you would need to provide a parent to mark the end of the chain. Span::source_callsite doesn't need such a stopper but here its use would be incorrect if the macro call itself (e.g. Err(s!(x))) was inside of a macro expansion.

    Since we don't have a parent (afaiaa), earlier I briefly tried to create a parent for find_ancestor_inside via tcx.hir().span_with_body(tcx.hir().parent_id(expr.hir_id)) I think but that didn't work. Maybe tcx.hir().get_enclosing_scope(/*???*/) could work, not sure. This approach is a catch-22 I believe.

  8. Ezrashaw commented on Apr 7, 2023

    @Ezrashaw
    Contributor

    Yeah, would that be the desired solution though? Can this be generalized to all the other type mismatch suggestions?

  9. fmease commented on Apr 7, 2023

    @fmease
    Member

    That's a good question. It was mostly an experiment to see if this specific issue can be solved with find_ancestor_inside.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsD-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions