1
Fork 0

Rollup merge of #133382 - mu001999-contrib:diag/fnitem, r=lcnr

Suggest considering casting fn item as fn pointer in more cases

Fixes #132648
This commit is contained in:
Matthias Krüger 2025-01-29 15:29:27 +01:00 committed by GitHub
commit f8d103df43
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 114 additions and 6 deletions

View file

@ -165,6 +165,8 @@ trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime r
trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
trait_selection_fn_consider_casting_both = consider casting both fn items to fn pointers using `as {$sig}`
trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same
trait_selection_fps_cast = consider casting to a fn pointer
trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`

View file

@ -1844,7 +1844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.suggest_tuple_pattern(cause, &exp_found, diag);
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
self.suggest_function_pointers(cause, span, &exp_found, diag);
self.suggest_function_pointers(cause, span, &exp_found, terr, diag);
self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
}
}

View file

@ -12,6 +12,7 @@ use rustc_middle::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
StatementAsExpression,
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
use rustc_span::{Span, sym};
@ -20,7 +21,7 @@ use tracing::debug;
use crate::error_reporting::TypeErrCtxt;
use crate::error_reporting::infer::hir::Path;
use crate::errors::{
ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
ConsiderAddingAwait, FnConsiderCasting, FnConsiderCastingBoth, FnItemsAreDistinct, FnUniqTypes,
FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
};
@ -381,14 +382,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
pub(super) fn suggest_function_pointers(
pub fn suggest_function_pointers_impl(
&self,
cause: &ObligationCause<'tcx>,
span: Span,
span: Option<Span>,
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut Diag<'_>,
) {
debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
let ty::error::ExpectedFound { expected, found } = exp_found;
let expected_inner = expected.peel_refs();
let found_inner = found.peel_refs();
@ -411,6 +410,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return;
}
let Some(span) = span else {
let casting = format!("{fn_name} as {sig}");
diag.subdiagnostic(FnItemsAreDistinct);
diag.subdiagnostic(FnConsiderCasting { casting });
return;
};
let sugg = match (expected.is_ref(), found.is_ref()) {
(true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
(false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
@ -445,6 +451,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
let fn_name = self.tcx.def_path_str_with_args(*did2, args2);
let Some(span) = span else {
diag.subdiagnostic(FnConsiderCastingBoth { sig: *expected_sig });
return;
};
let sug = if found.is_ref() {
FunctionPointerSuggestion::CastBothRef {
span,
@ -488,6 +500,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
}
pub(super) fn suggest_function_pointers(
&self,
cause: &ObligationCause<'tcx>,
span: Span,
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
terr: TypeError<'tcx>,
diag: &mut Diag<'_>,
) {
debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
if exp_found.expected.peel_refs().is_fn() && exp_found.found.peel_refs().is_fn() {
self.suggest_function_pointers_impl(Some(span), exp_found, diag);
} else if let TypeError::Sorts(exp_found) = terr {
self.suggest_function_pointers_impl(None, &exp_found, diag);
}
}
pub fn should_suggest_as_ref_kind(
&self,
expected: Ty<'tcx>,

View file

@ -1969,6 +1969,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
StringPart::highlighted(exp_found.found.to_string()),
StringPart::normal("`"),
]);
self.suggest_function_pointers_impl(None, &exp_found, err);
}
true

View file

@ -1496,6 +1496,12 @@ pub struct FnConsiderCasting {
pub casting: String,
}
#[derive(Subdiagnostic)]
#[help(trait_selection_fn_consider_casting_both)]
pub struct FnConsiderCastingBoth<'a> {
pub sig: Binder<'a, FnSig<'a>>,
}
#[derive(Subdiagnostic)]
pub enum SuggestAccessingField<'a> {
#[suggestion(

View file

@ -0,0 +1,9 @@
//@ edition: 2021
fn foo() {}
fn main() {
let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect(); //~ ERROR
let _: Vec<fn()> = [foo].into_iter().collect(); //~ ERROR
let _: Vec<fn()> = Vec::from([foo]); //~ ERROR
}

View file

@ -0,0 +1,59 @@
error[E0277]: a value of type `Vec<(&str, fn())>` cannot be built from an iterator over elements of type `(&str, fn() {foo})`
--> $DIR/casting-fn-item-to-fn-pointer.rs:6:59
|
LL | let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
| ^^^^^^^ value of type `Vec<(&str, fn())>` cannot be built from `std::iter::Iterator<Item=(&str, fn() {foo})>`
|
= help: the trait `FromIterator<(&_, fn() {foo})>` is not implemented for `Vec<(&str, fn())>`
but trait `FromIterator<(&_, fn())>` is implemented for it
= help: for that trait implementation, expected `fn()`, found `fn() {foo}`
= note: fn items are distinct from fn pointers
= help: consider casting the fn item to a fn pointer: `foo as fn()`
note: the method call chain might not have had the expected associated types
--> $DIR/casting-fn-item-to-fn-pointer.rs:6:47
|
LL | let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
| -------------- ^^^^^^^^^^^ `Iterator::Item` is `(&str, fn() {foo})` here
| |
| this expression has type `[(&str, fn() {foo}); 1]`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error[E0277]: a value of type `Vec<fn()>` cannot be built from an iterator over elements of type `fn() {foo}`
--> $DIR/casting-fn-item-to-fn-pointer.rs:7:42
|
LL | let _: Vec<fn()> = [foo].into_iter().collect();
| ^^^^^^^ value of type `Vec<fn()>` cannot be built from `std::iter::Iterator<Item=fn() {foo}>`
|
= help: the trait `FromIterator<fn() {foo}>` is not implemented for `Vec<fn()>`
but trait `FromIterator<fn()>` is implemented for it
= help: for that trait implementation, expected `fn()`, found `fn() {foo}`
= note: fn items are distinct from fn pointers
= help: consider casting the fn item to a fn pointer: `foo as fn()`
note: the method call chain might not have had the expected associated types
--> $DIR/casting-fn-item-to-fn-pointer.rs:7:30
|
LL | let _: Vec<fn()> = [foo].into_iter().collect();
| ----- ^^^^^^^^^^^ `Iterator::Item` is `fn() {foo}` here
| |
| this expression has type `[fn() {foo}; 1]`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error[E0308]: mismatched types
--> $DIR/casting-fn-item-to-fn-pointer.rs:8:24
|
LL | let _: Vec<fn()> = Vec::from([foo]);
| --------- ^^^^^^^^^^^^^^^^ expected `Vec<fn()>`, found `Vec<fn() {foo}>`
| |
| expected due to this
|
= note: expected struct `Vec<fn()>`
found struct `Vec<fn() {foo}>`
= note: fn items are distinct from fn pointers
= help: consider casting the fn item to a fn pointer: `foo as fn()`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.

View file

@ -10,6 +10,8 @@ LL | Self { map }
|
= note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
= note: fn items are distinct from fn pointers
= help: consider casting the fn item to a fn pointer: `<Struct as Trait>::do_something::<'_> as fn(u8) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>`
error: aborting due to 1 previous error