diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8df211b0840ec..aa67ca3a60397 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1027,6 +1027,7 @@ symbols! { format_args_capture, format_args_macro, format_args_nl, + format_args_nl_macro, format_argument, format_arguments, format_count, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 78f9287b407b3..17ca6d7fc37d1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -7,6 +7,7 @@ pub mod on_unimplemented_format; mod overflow; pub mod suggestions; +use std::cmp::Reverse; use std::{fmt, iter}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -21,7 +22,7 @@ use rustc_infer::traits::{ }; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; +use rustc_span::{ErrorGuaranteed, ExpnKind, Span, sym}; use tracing::{info, instrument}; pub use self::overflow::*; @@ -136,6 +137,15 @@ pub enum DefIdOrName { Name(&'static str), } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +enum ErrorSortKey { + SubtypeFormat(Reverse), + OtherKind, + ClauseTraitSized, + Coerce, + ClauseWellFormed, +} + impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn report_fulfillment_errors( &self, @@ -162,15 +172,33 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics // with more relevant type information and hide redundant E0282 errors. - errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) - if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => - { - 1 + errors.sort_by_key(|e| { + let span = e.obligation.cause.span; + let outer_expn_data = span.ctxt().outer_expn_data(); + + match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Subtype(_) + if let Some(def_id) = outer_expn_data.macro_def_id + && (self.tcx.is_diagnostic_item(sym::format_args_nl_macro, def_id) + || self.tcx.is_diagnostic_item(sym::format_args_macro, def_id)) + && self.is_source_span(span) => + { + let source_map = self.tcx.sess.source_map(); + let (_, _, lo_col, _, _) = source_map.span_to_location_info(span); + + ErrorSortKey::SubtypeFormat(Reverse(lo_col)) + } + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) + if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => + { + ErrorSortKey::ClauseTraitSized + } + ty::PredicateKind::Coerce(_) => ErrorSortKey::Coerce, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => { + ErrorSortKey::ClauseWellFormed + } + _ => ErrorSortKey::OtherKind, } - ty::PredicateKind::Coerce(_) => 2, - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, - _ => 0, }); for (index, error) in errors.iter().enumerate() { @@ -250,6 +278,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) } + fn is_source_span(&self, span: Span) -> bool { + let source_map = self.tcx.sess.source_map(); + + let outer_expn_data = span.ctxt().outer_expn_data(); + let outer_callsite = outer_expn_data.call_site.source_callsite(); + + let span_info = source_map.span_to_location_info(span); + let outer_info = source_map.span_to_location_info(outer_callsite); + + match (span_info, outer_info) { + ((Some(sf1), _, _, _, _), (Some(sf2), _, _, _, _)) => sf1.src_hash == sf2.src_hash, + _ => false, + } + } + #[instrument(skip(self), level = "debug")] fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { let mut error = FulfillmentError { diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7dc8c060cd5bc..e2beb525697c3 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1027,6 +1027,7 @@ pub(crate) mod builtin { reason = "`format_args_nl` is only for internal \ language use and is subject to change" )] + #[rustc_diagnostic_item = "format_args_nl_macro"] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] #[macro_export] diff --git a/tests/ui/errors/span-format_args-issue-140578.rs b/tests/ui/errors/span-format_args-issue-140578.rs new file mode 100644 index 0000000000000..3d421f27f91b5 --- /dev/null +++ b/tests/ui/errors/span-format_args-issue-140578.rs @@ -0,0 +1,11 @@ +fn check_format_args() { + print!("{:?} {a} {a:?}", [], a = 1 + 1); + //~^ ERROR type annotations needed +} + +fn check_format_args_nl() { + println!("{:?} {a} {a:?}", [], a = 1 + 1); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/errors/span-format_args-issue-140578.stderr b/tests/ui/errors/span-format_args-issue-140578.stderr new file mode 100644 index 0000000000000..42245c31982cd --- /dev/null +++ b/tests/ui/errors/span-format_args-issue-140578.stderr @@ -0,0 +1,19 @@ +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:2:28 + | +LL | print!("{:?} {a} {a:?}", [], a = 1 + 1); + | ^^ cannot infer type + | + = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the macro `print` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:7:30 + | +LL | println!("{:?} {a} {a:?}", [], a = 1 + 1); + | ^^ cannot infer type + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`.