From c5320454ed47736d17d1e07438e27345f08782bc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 8 Apr 2025 05:54:44 +0000 Subject: [PATCH 1/2] Improve presentation of closure signature mismatch from Fn trait goal --- .../traits/fulfillment_errors.rs | 76 +++++++++++++------ .../issue-62529-3.stderr | 4 +- tests/ui/implied-bounds/issue-100690.stderr | 4 +- ...-arg-type-mismatch-issue-45727.next.stderr | 8 +- .../ui/trait-bounds/mismatch-fn-trait.stderr | 8 +- 5 files changed, 63 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index bc45fc11e9b..a01574f2826 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2,6 +2,7 @@ use core::ops::ControlFlow; use std::borrow::Cow; use std::path::PathBuf; +use rustc_abi::ExternAbi; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; @@ -2799,32 +2800,57 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Note any argument mismatches - let given_ty = params.skip_binder(); + let ty::Tuple(given) = *params.skip_binder().kind() else { + return; + }; + let expected_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); - if let ty::Tuple(given) = given_ty.kind() - && let ty::Tuple(expected) = expected_ty.kind() - { - if expected.len() != given.len() { - // Note number of types that were expected and given - err.note( - format!( - "expected a closure taking {} argument{}, but one taking {} argument{} was given", - given.len(), - pluralize!(given.len()), - expected.len(), - pluralize!(expected.len()), - ) - ); - } else if !self.same_type_modulo_infer(given_ty, expected_ty) { - // Print type mismatch - let (expected_args, given_args) = self.cmp(given_ty, expected_ty); - err.note_expected_found( - &"a closure with arguments", - expected_args, - &"a closure with arguments", - given_args, - ); - } + let ty::Tuple(expected) = *expected_ty.kind() else { + return; + }; + + if expected.len() != given.len() { + // Note number of types that were expected and given + err.note(format!( + "expected a closure taking {} argument{}, but one taking {} argument{} was given", + given.len(), + pluralize!(given.len()), + expected.len(), + pluralize!(expected.len()), + )); + return; + } + + let given_ty = Ty::new_fn_ptr( + self.tcx, + params.rebind(self.tcx.mk_fn_sig( + given, + self.tcx.types.unit, + false, + hir::Safety::Safe, + ExternAbi::Rust, + )), + ); + let expected_ty = Ty::new_fn_ptr( + self.tcx, + trait_pred.rebind(self.tcx.mk_fn_sig( + expected, + self.tcx.types.unit, + false, + hir::Safety::Safe, + ExternAbi::Rust, + )), + ); + + if !self.same_type_modulo_infer(given_ty, expected_ty) { + // Print type mismatch + let (expected_args, given_args) = self.cmp(expected_ty, given_ty); + err.note_expected_found( + &"a closure with signature", + expected_args, + &"a closure with signature", + given_args, + ); } } diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr index 64707642eeb..36264b0d997 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr @@ -6,8 +6,8 @@ LL | call(f, ()); | | | required by a bound introduced by this call | - = note: expected a closure with arguments `((),)` - found a closure with arguments `(<_ as ATC<'a>>::Type,)` + = note: expected a closure with signature `for<'a> fn(<_ as ATC<'a>>::Type)` + found a closure with signature `fn(())` note: this is a known limitation of the trait solver that will be lifted in the future --> $DIR/issue-62529-3.rs:25:14 | diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr index 4964dccd551..d00895d8fc9 100644 --- a/tests/ui/implied-bounds/issue-100690.stderr +++ b/tests/ui/implied-bounds/issue-100690.stderr @@ -6,8 +6,8 @@ LL | real_dispatch(f) | | | required by a bound introduced by this call | - = note: expected a closure with arguments `(&mut UIView<'a, _>,)` - found a closure with arguments `(&mut UIView<'_, _>,)` + = note: expected a closure with signature `for<'a, 'b> fn(&'a mut UIView<'b, _>)` + found a closure with signature `fn(&mut UIView<'a, _>)` note: required by a bound in `real_dispatch` --> $DIR/issue-100690.rs:8:8 | diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr index b7161310619..7912ed4d707 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -7,8 +7,8 @@ LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); | required by a bound introduced by this call | = help: the trait `for<'a> FnMut(&'a as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` - = note: expected a closure with arguments `(i32,)` - found a closure with arguments `(& as Iterator>::Item,)` + = note: expected a closure with signature `for<'a> fn(&'a as Iterator>::Item)` + found a closure with signature `fn(i32)` note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL @@ -27,8 +27,8 @@ LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); | required by a bound introduced by this call | = help: the trait `for<'a> FnMut(&'a as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` - = note: expected a closure with arguments `(&&&i32,)` - found a closure with arguments `(& as Iterator>::Item,)` + = note: expected a closure with signature `for<'a> fn(&'a as Iterator>::Item)` + found a closure with signature `fn(&&&i32)` note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL diff --git a/tests/ui/trait-bounds/mismatch-fn-trait.stderr b/tests/ui/trait-bounds/mismatch-fn-trait.stderr index 519aa9ea3f3..051e660c2d1 100644 --- a/tests/ui/trait-bounds/mismatch-fn-trait.stderr +++ b/tests/ui/trait-bounds/mismatch-fn-trait.stderr @@ -6,8 +6,8 @@ LL | take(f) | | | required by a bound introduced by this call | - = note: expected a closure with arguments `(u32,)` - found a closure with arguments `(i32,)` + = note: expected a closure with signature `fn(i32)` + found a closure with signature `fn(u32)` note: required by a bound in `take` --> $DIR/mismatch-fn-trait.rs:1:18 | @@ -68,8 +68,8 @@ LL | take(f) | required by a bound introduced by this call | = note: `impl FnOnce(u32)` implements `FnOnce`, but it must implement `FnMut`, which is more general - = note: expected a closure with arguments `(u32,)` - found a closure with arguments `(i32,)` + = note: expected a closure with signature `fn(i32)` + found a closure with signature `fn(u32)` note: required by a bound in `take` --> $DIR/mismatch-fn-trait.rs:1:18 | From d940038636c3694c896988c5cb035da4456a2cb0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 8 Apr 2025 06:09:04 +0000 Subject: [PATCH 2/2] Remove unnecessary dyn Display in favor of str --- compiler/rustc_errors/src/diagnostic.rs | 8 ++++---- compiler/rustc_lint/src/lints.rs | 2 +- .../src/error_reporting/infer/region.rs | 2 +- .../src/error_reporting/traits/fulfillment_errors.rs | 4 ++-- compiler/rustc_trait_selection/src/errors.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 794502d7aae..bd13c413a4d 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -647,9 +647,9 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { #[rustc_lint_diagnostics] pub fn note_expected_found( &mut self, - expected_label: &dyn fmt::Display, + expected_label: &str, expected: DiagStyledString, - found_label: &dyn fmt::Display, + found_label: &str, found: DiagStyledString, ) -> &mut Self { self.note_expected_found_extra( @@ -665,9 +665,9 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { #[rustc_lint_diagnostics] pub fn note_expected_found_extra( &mut self, - expected_label: &dyn fmt::Display, + expected_label: &str, expected: DiagStyledString, - found_label: &dyn fmt::Display, + found_label: &str, found: DiagStyledString, expected_extra: DiagStyledString, found_extra: DiagStyledString, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 55d010e6d34..51214c8e8a4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -513,7 +513,7 @@ impl Subdiagnostic for BuiltinClashingExternSub<'_> { expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagStyledString::new(); found_str.push(self.found.fn_sig(self.tcx).to_string(), true); - diag.note_expected_found(&"", expected_str, &"", found_str); + diag.note_expected_found("", expected_str, "", found_str); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index c7f0a88f951..fcb98f740b0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -967,7 +967,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("...so that the {}", sup_trace.cause.as_requirement_str()), ); - err.note_expected_found(&"", sup_expected, &"", sup_found); + err.note_expected_found("", sup_expected, "", sup_found); return if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index a01574f2826..5648021f613 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2846,9 +2846,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Print type mismatch let (expected_args, given_args) = self.cmp(expected_ty, given_ty); err.note_expected_found( - &"a closure with signature", + "a closure with signature", expected_args, - &"a closure with signature", + "a closure with signature", given_args, ); } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 9f7bfe5101a..bb4aba9d29e 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -415,7 +415,7 @@ impl Subdiagnostic for RegionOriginNote<'_> { label_or_note(span, fluent::trait_selection_subtype); diag.arg("requirement", requirement); - diag.note_expected_found(&"", expected, &"", found); + diag.note_expected_found("", expected, "", found); } RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { // FIXME: this really should be handled at some earlier stage. Our