Repository: rust-lang/rust
Pull request #141070: Do not emit help when shorthand from macro when suggest `?` or `expect`
Author: login: xizheyin
Labels: name: T-compiler
description: Relevant to the compiler team, which will review and decide on the PR/issue.
name: S-waiting-on-bors
description: Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Created: 2025-05-16T09:07:39Z | Merged: 2025-05-17T13:11:18Z

Fixes #140659 

I didn't fully minimize the original bug, but I found a similar test case, and they have perhaps the same root cause. For the bug mentioned in #140659 , I also tested it locally and passed it.

Jieyou has worked on this part before, maybe r? @jieyouxu 

Linked issue #140659: Malformed suggestion for E0308 when macros are involved
I don't have the time to minimize this right now so I've committed the intermediate state that produces a pretty weird suggestion that's invalid:

```
error[E0308]: mismatched types
    --> crates/wasm-encoder/src/reencode.rs:1727:9
     |
1727 |         wasmparser::for_each_operator!(translate)
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `Result<u32, <T as Reencode>::Error>`
     |
     = note: expected type `u32`
                found enum `core::result::Result<u32, <T as Reencode>::Error>`
     = note: this error originates in the macro `wasmparser::for_each_operator` (in Nightly builds, run with -Z macro-backtrace for more info)
help: use the `?` operator to extract the `core::result::Result<u32, <T as Reencode>::Error>` value, propagating a `Result::Err` value to the caller
     |
1727 |         wasmparser::for_each_operator!(translate): tag_index?
     |                                                  ++++++++++++
```

You can find the reproducing code at https://github.com/nagisa/wasm-tools/tree/weird-diagnostic and running `cargo check --all-features`.

Reproduces both on stable and nightly:

```
cargo 1.88.0-nightly (7918c7eb5 2025-04-27)
release: 1.88.0-nightly
commit-hash: 7918c7eb59614c39f1c4e27e99d557720976bdd7
commit-date: 2025-04-27
host: x86_64-unknown-linux-gnu
libgit2: 1.9.0 (sys:0.20.0 vendored)
libcurl: 8.12.1-DEV (sys:0.4.80+curl-8.12.1 vendored ssl:OpenSSL/3.4.1)
ssl: OpenSSL 3.4.1 11 Feb 2025
os: NixOS 25.5.0 [64-bit]
```

```
cargo 1.86.0 (adf9b6ad1 2025-02-28)
release: 1.86.0
commit-hash: adf9b6ad14cfa10ff680d5806741a144f7163698
commit-date: 2025-02-28
host: x86_64-unknown-linux-gnu
libgit2: 1.9.0 (sys:0.20.0 vendored)
libcurl: 8.12.0-DEV (sys:0.4.79+curl-8.12.0 vendored ssl:OpenSSL/1.1.1w)
ssl: OpenSSL 1.1.1w  11 Sep 2023
os: NixOS 25.5.0 [64-bit]
```

<!-- TRIAGEBOT_START -->

<!-- TRIAGEBOT_ASSIGN_START -->

<!-- TRIAGEBOT_ASSIGN_DATA_START$${"user":"xizheyin"}$$TRIAGEBOT_ASSIGN_DATA_END -->

<!-- TRIAGEBOT_ASSIGN_END -->
<!-- TRIAGEBOT_END -->
Linked issue comments: user: login: xizheyin
created_at: 2025-05-14T07:26:36Z
body: @rustbot claim
author_association: MEMBER

Diff:
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 91eb1989864ff..d3618a6ae69a3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2034,6 +2034,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
+            Some(_) if expr.span.from_expansion() => return false,
             Some(ident) => format!(": {ident}{sugg}"),
             None => sugg.to_string(),
         };
diff --git a/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.rs b/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.rs
new file mode 100644
index 0000000000000..d71a7ff1d3d4d
--- /dev/null
+++ b/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.rs
@@ -0,0 +1,56 @@
+trait Reencode {
+    type Error;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error>;
+}
+
+struct Reencoder;
+impl Reencode for Reencoder {
+    type Error = &'static str;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error> {
+        Ok(tag)
+    }
+}
+
+
+enum Operator {
+    Suspend { tag_index: u32 },
+}
+
+enum Instruction {
+    Suspend { tag_index: u32 },
+}
+
+
+macro_rules! for_each_operator {
+    ($m:ident) => {
+        $m! {
+            Suspend { tag_index: u32 } => visit_suspend
+        }
+    };
+}
+
+
+fn process<T: Reencode>(op: &Operator, reencoder: &mut T) -> Instruction {
+    macro_rules! translate {
+        (Suspend { tag_index: $ty:ty } => $visit:ident) => {
+            match op {
+                Operator::Suspend { tag_index } => {
+                    let tag_index = reencoder.tag_index(*tag_index);
+
+                    // KEY POINT: Using field shorthand syntax where the compiler gets confused
+                    // Here tag_index is a Result<u32, E> but we're using it where u32 is expected
+                    Instruction::Suspend { tag_index } //~ ERROR mismatched types [E0308]
+                }
+            }
+        };
+    }
+
+    for_each_operator!(translate)
+}
+
+fn main() {
+    let mut reencoder = Reencoder;
+    let op = Operator::Suspend { tag_index: 1 };
+
+    let _ = process(&op, &mut reencoder);
+}
diff --git a/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.stderr b/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.stderr
new file mode 100644
index 0000000000000..12537754d8029
--- /dev/null
+++ b/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/macro-shorthand-issue-140659.rs:42:44
+   |
+LL |                     Instruction::Suspend { tag_index }
+   |                                            ^^^^^^^^^ expected `u32`, found `Result<u32, <T as Reencode>::Error>`
+...
+LL |     for_each_operator!(translate)
+   |     ----------------------------- in this macro invocation
+   |
+   = note: expected type `u32`
+              found enum `Result<u32, <T as Reencode>::Error>`
+   = note: this error originates in the macro `translate` which comes from the expansion of the macro `for_each_operator` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.fixed b/tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.fixed
similarity index 100%
rename from tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.fixed
rename to tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.fixed
diff --git a/tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.rs b/tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.rs
similarity index 100%
rename from tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.rs
rename to tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.rs
diff --git a/tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr b/tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.stderr
similarity index 100%
rename from tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr
rename to tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.stderr
diff --git a/tests/ui/typeck/suggest-arg-comma-delete-ice.rs b/tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.rs
similarity index 100%
rename from tests/ui/typeck/suggest-arg-comma-delete-ice.rs
rename to tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.rs
diff --git a/tests/ui/typeck/suggest-arg-comma-delete-ice.stderr b/tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.stderr
similarity index 100%
rename from tests/ui/typeck/suggest-arg-comma-delete-ice.stderr
rename to tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.stderr
diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed b/tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.fixed
similarity index 100%
rename from tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed
rename to tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.fixed
diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs b/tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.rs
similarity index 100%
rename from tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs
rename to tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.rs
diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr b/tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.stderr
similarity index 100%
rename from tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr
rename to tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.stderr
diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs b/tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.rs
similarity index 100%
rename from tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs
rename to tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.rs
diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr b/tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.stderr
similarity index 100%
rename from tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr
rename to tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.stderr


Reviews:
user: login: chenyukang
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T11:00:58Z
user: login: jieyouxu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T11:11:41Z
user: login: chenyukang
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T12:55:10Z
user: login: chenyukang
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T12:55:29Z
user: login: xizheyin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T13:34:12Z
user: login: xizheyin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T13:36:22Z
user: login: jieyouxu
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T13:37:40Z
user: login: xizheyin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T17:06:04Z

Review comments:
diff_hunk: @@ -2034,8 +2034,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
+            Some(_) if expr.span.from_expansion() => return false,
path: compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
user: login: chenyukang
body: I think we can remove more potential invalid suggestions if we add:

```rust
     if expr.span.from_expansion() {
            return false;
        }
```

at the start of `suggest_missing_unwrap_expect`.


created_at: 2025-05-16T11:00:47Z
author_association: MEMBER
path: tests/ui/typeck/macro-shorthand-issue-140659.rs
user: login: jieyouxu
body: Question: I *feel like* there's a `suggestion/` folder somewhere, but maybe I'm remembering another subfolder?
created_at: 2025-05-16T11:09:45Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,57 @@
+trait Reencode {
+    type Error;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error>;
+}
+
+struct Reencoder;
+impl Reencode for Reencoder {
+    type Error = &'static str;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error> {
+        Ok(tag)
+    }
+}
+
+
+enum Operator {
+    Suspend { tag_index: u32 },
+}
+
+enum Instruction {
+    Suspend { tag_index: u32 },
+}
+
+
+macro_rules! for_each_operator {
+    ($m:ident) => {
+        $m! {
+            Suspend { tag_index: u32 } => visit_suspend
+        }
+    };
+}
+
+
+fn process<T: Reencode>(op: &Operator, reencoder: &mut T) -> Instruction {
+    macro_rules! translate {
+        (Suspend { tag_index: $ty:ty } => $visit:ident) => {
+            match op {
+                Operator::Suspend { tag_index } => {
+                    let tag_index = reencoder.tag_index(*tag_index);
+
+                    // KEY POINT: Using field shorthand syntax where the compiler gets confused
+                    // Here tag_index is a Result<u32, E> but we're using it where u32 is expected
+                    Instruction::Suspend { tag_index } //~ ERROR mismatched types [E0308]
+                }
+            }
+        };
+    }
+
+    // This should give the specific error message with the wrong help suggestion
path: tests/ui/typeck/macro-shorthand-issue-140659.rs
user: login: jieyouxu
body: Question: do you mean "this previously gave the wrong help suggestion"? Or what do you mean by this comment?
created_at: 2025-05-16T11:11:02Z
author_association: MEMBER
diff_hunk: @@ -2034,8 +2034,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
+            Some(_) if expr.span.from_expansion() => return false,
path: compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
user: login: chenyukang
body: never mind, seems the above suggestion of https://github.com/rust-lang/rust/pull/141070/files#diff-a188fa3dba59dd225d4a65e08961d2937f6418bc6126716e001303bf946d6ee3R2018 could be valid for macro, such as https://github.com/chenyukang/rust/blob/c79bbfab78dcb0a72aa3b2bc35c00334b58bfe2e/tests/ui/typeck/question-mark-operator-suggestion-span.rs#L18
created_at: 2025-05-16T12:55:10Z
author_association: MEMBER
diff_hunk: @@ -2034,8 +2034,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
+            Some(_) if expr.span.from_expansion() => return false,
             Some(ident) => format!(": {ident}{sugg}"),
-            None => sugg.to_string(),
+            _ => sugg.to_string(),
path: compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
user: login: chenyukang
body: No need to change this line here?

created_at: 2025-05-16T12:55:28Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,57 @@
+trait Reencode {
+    type Error;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error>;
+}
+
+struct Reencoder;
+impl Reencode for Reencoder {
+    type Error = &'static str;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error> {
+        Ok(tag)
+    }
+}
+
+
+enum Operator {
+    Suspend { tag_index: u32 },
+}
+
+enum Instruction {
+    Suspend { tag_index: u32 },
+}
+
+
+macro_rules! for_each_operator {
+    ($m:ident) => {
+        $m! {
+            Suspend { tag_index: u32 } => visit_suspend
+        }
+    };
+}
+
+
+fn process<T: Reencode>(op: &Operator, reencoder: &mut T) -> Instruction {
+    macro_rules! translate {
+        (Suspend { tag_index: $ty:ty } => $visit:ident) => {
+            match op {
+                Operator::Suspend { tag_index } => {
+                    let tag_index = reencoder.tag_index(*tag_index);
+
+                    // KEY POINT: Using field shorthand syntax where the compiler gets confused
+                    // Here tag_index is a Result<u32, E> but we're using it where u32 is expected
+                    Instruction::Suspend { tag_index } //~ ERROR mismatched types [E0308]
+                }
+            }
+        };
+    }
+
+    // This should give the specific error message with the wrong help suggestion
path: tests/ui/typeck/macro-shorthand-issue-140659.rs
user: login: xizheyin
body: lol...This is the comment I added in the first commit, but I forgot to delete it in the second commit.
created_at: 2025-05-16T13:34:12Z
author_association: MEMBER
path: tests/ui/typeck/macro-shorthand-issue-140659.rs
user: login: xizheyin
body: Yes, do we need to put the suggestion mistakes there? I feel that things in there are a little messy. Maybe we need to clean it up.
created_at: 2025-05-16T13:36:22Z
author_association: MEMBER
path: tests/ui/typeck/macro-shorthand-issue-140659.rs
user: login: jieyouxu
body: I don't mean `tests/ui/suggestions/` (IMO that's a really bad folder because it's so generic), I thought there was a `tests/ui/typeck/suggestions/` but maybe I was thinking of another folder.
created_at: 2025-05-16T13:37:39Z
author_association: MEMBER
path: tests/ui/typeck/macro-shorthand-issue-140659.rs
user: login: xizheyin
body: There does not exists a tests/ui/typeck/suggestions, I will create it.
created_at: 2025-05-16T16:54:24Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,56 @@
+trait Reencode {
+    type Error;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error>;
+}
+
+struct Reencoder;
+impl Reencode for Reencoder {
+    type Error = &'static str;
+    fn tag_index(&mut self, tag: u32) -> Result<u32, Self::Error> {
+        Ok(tag)
+    }
+}
+
+
+enum Operator {
+    Suspend { tag_index: u32 },
+}
+
+enum Instruction {
+    Suspend { tag_index: u32 },
+}
+
+
+macro_rules! for_each_operator {
+    ($m:ident) => {
+        $m! {
+            Suspend { tag_index: u32 } => visit_suspend
+        }
+    };
+}
+
+
+fn process<T: Reencode>(op: &Operator, reencoder: &mut T) -> Instruction {
+    macro_rules! translate {
+        (Suspend { tag_index: $ty:ty } => $visit:ident) => {
+            match op {
+                Operator::Suspend { tag_index } => {
+                    let tag_index = reencoder.tag_index(*tag_index);
+
+                    // KEY POINT: Using field shorthand syntax where the compiler gets confused
+                    // Here tag_index is a Result<u32, E> but we're using it where u32 is expected
+                    Instruction::Suspend { tag_index } //~ ERROR mismatched types [E0308]
+                }
+            }
+        };
+    }
+
+    for_each_operator!(translate)
path: tests/ui/typeck/suggestions/macro-shorthand-issue-140659.rs
user: login: xizheyin
body: I delete the unused comment.
created_at: 2025-05-16T17:04:05Z
author_association: MEMBER
diff_hunk: @@ -2034,6 +2034,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
+            Some(_) if expr.span.from_expansion() => return false,
             Some(ident) => format!(": {ident}{sugg}"),
             None => sugg.to_string(),
path: compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
user: login: xizheyin
body: Here remains unchanged.
created_at: 2025-05-16T17:04:47Z
author_association: MEMBER
path: tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.fixed
user: login: xizheyin
body: I create `tests/ui/typeck/suggestions/` amd move some testcases to it.
created_at: 2025-05-16T17:05:58Z
author_association: MEMBER

PR comments:
user: login: jieyouxu
created_at: 2025-05-16T11:08:58Z
body: r? chenyukang (since you're already looking at it, but I can take the review back if you're busy)
author_association: MEMBER
user: login: chenyukang
created_at: 2025-05-16T17:39:43Z
body: 
@bors r+ rollup


author_association: MEMBER
user: login: bors
created_at: 2025-05-16T17:39:47Z
body: :pushpin: Commit 1c17324c7d82812b3e23902cd118b8ce77e9592c has been approved by `chenyukang`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust) for this repository.

<!-- @bors r=chenyukang 1c17324c7d82812b3e23902cd118b8ce77e9592c -->
<!-- homu: {"type":"Approved","sha":"1c17324c7d82812b3e23902cd118b8ce77e9592c","approver":"chenyukang","queue":"https://bors.rust-lang.org/homu/queue/rust"} -->
author_association: COLLABORATOR