From b0812d9b249ed04c2624a22c05201c9bc402ba42 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 7 Aug 2025 19:33:56 +0800 Subject: [PATCH 1/2] Add test sugg-swap-equality-in-macro Signed-off-by: xizheyin --- .../auxiliary/extern-macro-issue-139050.rs | 15 ++++++ ...ugg-swap-equality-in-macro-issue-139050.rs | 34 ++++++++++++++ ...swap-equality-in-macro-issue-139050.stderr | 46 +++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs create mode 100644 tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs create mode 100644 tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr diff --git a/tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs b/tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs new file mode 100644 index 0000000000000..a9b0cf7559e4a --- /dev/null +++ b/tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs @@ -0,0 +1,15 @@ +#[macro_export] +macro_rules! eq { + (assert $a:expr, $b:expr) => { + match (&$a, &$b) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + panic!( + "assertion failed: `(left == right)`\n left: `{:?}`,\n right: `{:?}`", + left_val, right_val + ); + } + } + } + }; +} \ No newline at end of file diff --git a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs new file mode 100644 index 0000000000000..d392487d03051 --- /dev/null +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs @@ -0,0 +1,34 @@ +// if we use lhs == rhs in a macro, we should not suggest to swap the equality +// because the origin span of lhs and rhs can not be found. See issue #139050 + +//@ aux-build:extern-macro-issue-139050.rs +//@ aux-crate:ext=extern-macro-issue-139050.rs + +extern crate ext; + +use std::fmt::Debug; + +macro_rules! eq_local { + (assert $a:expr, $b:expr) => { + match (&$a, &$b) { + (left_val, right_val) => { + if !(*left_val == *right_val) { //~ ERROR mismatched types [E0308] + panic!( + "assertion failed: `(left == right)`\n left: `{:?}`,\n right: `{:?}`", + left_val, right_val + ); + } + } + } + }; +} + +pub fn foo(mut iter: I, value: &I::Item) +where + Item: Eq + Debug, //~ ERROR cannot find type `Item` in this scope [E0412] +{ + ext::eq!(assert iter.next(), Some(value)); //~ ERROR mismatched types [E0308] + eq_local!(assert iter.next(), Some(value)); +} +fn main() {} + diff --git a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr new file mode 100644 index 0000000000000..b4c060e21c8e5 --- /dev/null +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr @@ -0,0 +1,46 @@ +error[E0412]: cannot find type `Item` in this scope + --> $DIR/sugg-swap-equality-in-macro-issue-139050.rs:28:5 + | +LL | Item: Eq + Debug, + | ^^^^ not found in this scope + +error[E0308]: mismatched types + --> $DIR/sugg-swap-equality-in-macro-issue-139050.rs:30:5 + | +LL | ext::eq!(assert iter.next(), Some(value)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Option<::Item>`, found `Option<&::Item>` + | + = note: expected enum `Option<_>` + found enum `Option<&_>` + = note: `Option<&::Item>` implements `PartialEq::Item>>` + = note: this error originates in the macro `ext::eq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider swapping the equality + --> $DIR/auxiliary/extern-macro-issue-139050.rs:6:22 + | +LL - if !(*left_val == *right_val) { +LL + if !(*right_val == *left_val) { + | + +error[E0308]: mismatched types + --> $DIR/sugg-swap-equality-in-macro-issue-139050.rs:15:35 + | +LL | if !(*left_val == *right_val) { + | ^^^^^^^^^^ expected `Option<::Item>`, found `Option<&::Item>` +... +LL | eq_local!(assert iter.next(), Some(value)); + | ------------------------------------------ in this macro invocation + | + = note: expected enum `Option<_>` + found enum `Option<&_>` + = note: `Option<&::Item>` implements `PartialEq::Item>>` + = note: this error originates in the macro `eq_local` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider swapping the equality + | +LL - if !(*left_val == *right_val) { +LL + if !(*right_val == *left_val) { + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0412. +For more information about an error, try `rustc --explain E0308`. From e73c1486f3b380123c69f8a3b2623f7552159c08 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 7 Aug 2025 19:46:24 +0800 Subject: [PATCH 2/2] Suggest swapping the equality in user-written code Signed-off-by: xizheyin --- .../src/fn_ctxt/suggestions.rs | 24 +++++++++++++------ .../auxiliary/extern-macro-issue-139050.rs | 4 ++-- ...ugg-swap-equality-in-macro-issue-139050.rs | 5 ++-- ...swap-equality-in-macro-issue-139050.stderr | 13 +++++----- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 2345cdab208e3..c4486818791d2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -3539,15 +3539,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .must_apply_modulo_regions() { let sm = self.tcx.sess.source_map(); - if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_expr.span) - && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_expr.span) + // If the span of rhs_expr or lhs_expr is in an external macro, + // we should find the user-written code span. See issue #139050 + if let Some(rhs_span) = rhs_expr.span.find_ancestor_not_from_extern_macro(sm) + && let Some(lhs_span) = lhs_expr.span.find_ancestor_not_from_extern_macro(sm) + && let Ok(rhs_snippet) = sm.span_to_snippet(rhs_span) + && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_span) { err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`")); - err.multipart_suggestion( - "consider swapping the equality", - vec![(lhs_expr.span, rhs_snippet), (rhs_expr.span, lhs_snippet)], - Applicability::MaybeIncorrect, - ); + if rhs_span != lhs_span { + err.multipart_suggestion( + "consider swapping the equality", + vec![(lhs_span, rhs_snippet), (rhs_span, lhs_snippet)], + Applicability::MaybeIncorrect, + ); + } else { + // rhs_span and lhs_span are the same because it from extern macro. + // we should suggest to swap two arguments of the equality + err.span_help(rhs_span, "consider swapping two arguments of the equality"); + } } } } diff --git a/tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs b/tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs index a9b0cf7559e4a..9e20c86adabce 100644 --- a/tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs +++ b/tests/ui/typeck/auxiliary/extern-macro-issue-139050.rs @@ -1,5 +1,5 @@ #[macro_export] -macro_rules! eq { +macro_rules! eq { (assert $a:expr, $b:expr) => { match (&$a, &$b) { (left_val, right_val) => { @@ -12,4 +12,4 @@ macro_rules! eq { } } }; -} \ No newline at end of file +} diff --git a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs index d392487d03051..e7dfd41944ae1 100644 --- a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs @@ -8,7 +8,7 @@ extern crate ext; use std::fmt::Debug; -macro_rules! eq_local { +macro_rules! eq_local { (assert $a:expr, $b:expr) => { match (&$a, &$b) { (left_val, right_val) => { @@ -28,7 +28,6 @@ where Item: Eq + Debug, //~ ERROR cannot find type `Item` in this scope [E0412] { ext::eq!(assert iter.next(), Some(value)); //~ ERROR mismatched types [E0308] - eq_local!(assert iter.next(), Some(value)); + eq_local!(assert iter.next(), Some(value)); } fn main() {} - diff --git a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr index b4c060e21c8e5..317a626c4e8ca 100644 --- a/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr @@ -13,13 +13,12 @@ LL | ext::eq!(assert iter.next(), Some(value)); = note: expected enum `Option<_>` found enum `Option<&_>` = note: `Option<&::Item>` implements `PartialEq::Item>>` - = note: this error originates in the macro `ext::eq` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider swapping the equality - --> $DIR/auxiliary/extern-macro-issue-139050.rs:6:22 - | -LL - if !(*left_val == *right_val) { -LL + if !(*right_val == *left_val) { +help: consider swapping two arguments of the equality + --> $DIR/sugg-swap-equality-in-macro-issue-139050.rs:30:5 | +LL | ext::eq!(assert iter.next(), Some(value)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `ext::eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/sugg-swap-equality-in-macro-issue-139050.rs:15:35 @@ -27,7 +26,7 @@ error[E0308]: mismatched types LL | if !(*left_val == *right_val) { | ^^^^^^^^^^ expected `Option<::Item>`, found `Option<&::Item>` ... -LL | eq_local!(assert iter.next(), Some(value)); +LL | eq_local!(assert iter.next(), Some(value)); | ------------------------------------------ in this macro invocation | = note: expected enum `Option<_>`