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 new file mode 100644 index 0000000000000..9e20c86adabce --- /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 + ); + } + } + } + }; +} 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..e7dfd41944ae1 --- /dev/null +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.rs @@ -0,0 +1,33 @@ +// 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..c53bbd846f33a --- /dev/null +++ b/tests/ui/typeck/sugg-swap-equality-in-macro-issue-139050.stderr @@ -0,0 +1,45 @@ +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>>` +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 + | +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`.