From 74b9f8ef17402efcf0e9bbe8800349fb102f0860 Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Sun, 11 May 2025 14:23:03 +0900 Subject: [PATCH 1/6] Fix unuseful span in type error in some format_args!() invocations --- .../src/error_reporting/traits/mod.rs | 53 ++++++++++++++++--- .../errors/span-format_args-issue-140578.rs | 11 ++++ .../span-format_args-issue-140578.stderr | 19 +++++++ 3 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 tests/ui/errors/span-format_args-issue-140578.rs create mode 100644 tests/ui/errors/span-format_args-issue-140578.stderr 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..aa9ed2d951740 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}; @@ -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,42 @@ 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 matches! ( + outer_expn_data.kind, + ExpnKind::Macro(_, name) if matches!( + name.as_str().rsplit("::").next(), + Some("format_args" | "format_args_nl") + ) + ) => + { + let sm = self.tcx.sess.source_map(); + let lc = sm.span_to_location_info(span); + + if sm.span_to_embeddable_string(span) + == sm.span_to_embeddable_string(outer_expn_data.call_site) + { + ErrorSortKey::OtherKind + } else { + ErrorSortKey::SubtypeFormat(Reverse(lc.2)) + } + } + 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() { 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`. From b544231788e745c5664e8eca69957ef18cd21cce Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Fri, 23 May 2025 09:31:29 +0900 Subject: [PATCH 2/6] Use is_diagnostic_item to detect format_args/format_args_nl --- compiler/rustc_span/src/symbol.rs | 1 + .../src/error_reporting/traits/mod.rs | 15 ++++++++------- library/core/src/macros/mod.rs | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) 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 aa9ed2d951740..0f0b0a2c8d1d7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -178,13 +178,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Subtype(_) - if matches! ( - outer_expn_data.kind, - ExpnKind::Macro(_, name) if matches!( - name.as_str().rsplit("::").next(), - Some("format_args" | "format_args_nl") - ) - ) => + if let Some(def_id) = outer_expn_data.macro_def_id + && (self + .tcx + .is_diagnostic_item(rustc_span::sym::format_args_nl_macro, def_id) + || self.tcx.is_diagnostic_item( + rustc_span::sym::format_args_macro, + def_id, + )) => { let sm = self.tcx.sess.source_map(); let lc = sm.span_to_location_info(span); diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7dc8c060cd5bc..073664d3ef813 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1012,6 +1012,7 @@ pub(crate) mod builtin { /// /// This macro will be removed once `format_args` is allowed in const contexts. #[unstable(feature = "const_format_args", issue = "none")] + #[rustc_diagnostic_item = "format_args_nl_macro"] #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] #[rustc_builtin_macro] #[macro_export] From d0cdf80e0cfaf5209f1ff344323e936ec850a4fb Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Fri, 23 May 2025 12:55:46 +0900 Subject: [PATCH 3/6] Fix rustc_diagnostic_item of format_args_nl_macro --- library/core/src/macros/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 073664d3ef813..e2beb525697c3 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1012,7 +1012,6 @@ pub(crate) mod builtin { /// /// This macro will be removed once `format_args` is allowed in const contexts. #[unstable(feature = "const_format_args", issue = "none")] - #[rustc_diagnostic_item = "format_args_nl_macro"] #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] #[rustc_builtin_macro] #[macro_export] @@ -1028,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] From a041ee2aff0bc9187c70fc7daae3e6d15348347e Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Sat, 24 May 2025 03:38:16 +0900 Subject: [PATCH 4/6] Fix sorting logic for ErrorSortKey::SubtypeFormat --- .../src/error_reporting/traits/mod.rs | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) 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 0f0b0a2c8d1d7..17ca6d7fc37d1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -22,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::*; @@ -179,24 +179,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { 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(rustc_span::sym::format_args_nl_macro, def_id) - || self.tcx.is_diagnostic_item( - rustc_span::sym::format_args_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 sm = self.tcx.sess.source_map(); - let lc = sm.span_to_location_info(span); - - if sm.span_to_embeddable_string(span) - == sm.span_to_embeddable_string(outer_expn_data.call_site) - { - ErrorSortKey::OtherKind - } else { - ErrorSortKey::SubtypeFormat(Reverse(lc.2)) - } + 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) => @@ -288,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 { From 9beea6fe35a99dc3e3400733d20c0f18b2e7d012 Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Sat, 24 May 2025 10:57:02 +0900 Subject: [PATCH 5/6] Fix SubtypeFormat sorting for unformmated code --- .../src/error_reporting/traits/mod.rs | 30 ++++++------------- .../errors/span-format_args-issue-140578.rs | 21 +++++++++++++ .../span-format_args-issue-140578.stderr | 26 +++++++++++++++- 3 files changed, 55 insertions(+), 22 deletions(-) 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 17ca6d7fc37d1..a169038f73bd5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -139,7 +139,7 @@ pub enum DefIdOrName { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] enum ErrorSortKey { - SubtypeFormat(Reverse), + SubtypeFormat(Reverse<(usize, usize)>), OtherKind, ClauseTraitSized, Coerce, @@ -175,18 +175,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { errors.sort_by_key(|e| { let span = e.obligation.cause.span; let outer_expn_data = span.ctxt().outer_expn_data(); + let source_span = outer_expn_data.call_site.source_callsite(); + let source_map = self.tcx.sess.source_map(); match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Subtype(_) if let Some(def_id) = outer_expn_data.macro_def_id + && let (Some(span_file), row, col, ..) = + source_map.span_to_location_info(span) + && let (Some(source_file), ..) = + source_map.span_to_location_info(source_span) && (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) => + && span_file.src_hash == source_file.src_hash => { - let source_map = self.tcx.sess.source_map(); - let (_, _, lo_col, _, _) = source_map.span_to_location_info(span); - - ErrorSortKey::SubtypeFormat(Reverse(lo_col)) + ErrorSortKey::SubtypeFormat(Reverse((row, col))) } ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => @@ -278,21 +281,6 @@ 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/tests/ui/errors/span-format_args-issue-140578.rs b/tests/ui/errors/span-format_args-issue-140578.rs index 3d421f27f91b5..6c55101779561 100644 --- a/tests/ui/errors/span-format_args-issue-140578.rs +++ b/tests/ui/errors/span-format_args-issue-140578.rs @@ -8,4 +8,25 @@ fn check_format_args_nl() { //~^ ERROR type annotations needed } +fn check_multi1() { + println!("{:?} {:?} {a} {a:?}", [], [], a = 1 + 1); + //~^ ERROR type annotations needed +} + +fn check_multi2() { + println!("{:?} {:?} {a} {a:?} {b:?}", [], [], a = 1 + 1, b = []); + //~^ ERROR type annotations needed +} + +fn check_unformatted() { + println!(" + {:?} {:?} +{a} +{a:?}", + [], + [], + //~^ ERROR type annotations needed +a = 1 + 1); +} + fn main() {} diff --git a/tests/ui/errors/span-format_args-issue-140578.stderr b/tests/ui/errors/span-format_args-issue-140578.stderr index 42245c31982cd..df7f6c4ae01ba 100644 --- a/tests/ui/errors/span-format_args-issue-140578.stderr +++ b/tests/ui/errors/span-format_args-issue-140578.stderr @@ -14,6 +14,30 @@ LL | println!("{:?} {a} {a:?}", [], a = 1 + 1); | = 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 +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:12:39 + | +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[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:17:64 + | +LL | println!("{:?} {:?} {a} {a:?} {b:?}", [], [], a = 1 + 1, b = []); + | ^^ 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[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:27:2 + | +LL | [], + | ^^ 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 5 previous errors For more information about this error, try `rustc --explain E0282`. From 73c88d218cb8affaa2177b11d9de289ae106631f Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Sat, 24 May 2025 12:59:10 +0900 Subject: [PATCH 6/6] Modify SubtypeFormat --- .../src/error_reporting/traits/mod.rs | 5 ++--- tests/ui/errors/span-format_args-issue-140578.rs | 2 +- .../ui/errors/span-format_args-issue-140578.stderr | 14 +++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) 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 a169038f73bd5..828db296ad342 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -7,7 +7,6 @@ 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}; @@ -139,7 +138,7 @@ pub enum DefIdOrName { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] enum ErrorSortKey { - SubtypeFormat(Reverse<(usize, usize)>), + SubtypeFormat(usize, usize), OtherKind, ClauseTraitSized, Coerce, @@ -189,7 +188,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::format_args_macro, def_id)) && span_file.src_hash == source_file.src_hash => { - ErrorSortKey::SubtypeFormat(Reverse((row, col))) + ErrorSortKey::SubtypeFormat(row, col) } ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => diff --git a/tests/ui/errors/span-format_args-issue-140578.rs b/tests/ui/errors/span-format_args-issue-140578.rs index 6c55101779561..8c91ded833753 100644 --- a/tests/ui/errors/span-format_args-issue-140578.rs +++ b/tests/ui/errors/span-format_args-issue-140578.rs @@ -24,8 +24,8 @@ fn check_unformatted() { {a} {a:?}", [], + //~^ ERROR type annotations needed [], - //~^ ERROR type annotations needed a = 1 + 1); } diff --git a/tests/ui/errors/span-format_args-issue-140578.stderr b/tests/ui/errors/span-format_args-issue-140578.stderr index df7f6c4ae01ba..6a273e5cd515c 100644 --- a/tests/ui/errors/span-format_args-issue-140578.stderr +++ b/tests/ui/errors/span-format_args-issue-140578.stderr @@ -15,26 +15,26 @@ LL | println!("{:?} {a} {a:?}", [], a = 1 + 1); = 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[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:12:39 + --> $DIR/span-format_args-issue-140578.rs:12:35 | LL | println!("{:?} {:?} {a} {a:?}", [], [], a = 1 + 1); - | ^^ cannot infer type + | ^^ 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[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:17:64 + --> $DIR/span-format_args-issue-140578.rs:17:41 | LL | println!("{:?} {:?} {a} {a:?} {b:?}", [], [], a = 1 + 1, b = []); - | ^^ cannot infer type + | ^^ 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[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:27:2 + --> $DIR/span-format_args-issue-140578.rs:26:9 | -LL | [], - | ^^ cannot infer type +LL | [], + | ^^ 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)