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:
commit
f8d103df43
8 changed files with 114 additions and 6 deletions
|
@ -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 = 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_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 = consider casting to a fn pointer
|
||||||
trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
|
trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
|
||||||
|
|
|
@ -1844,7 +1844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
self.suggest_tuple_pattern(cause, &exp_found, diag);
|
self.suggest_tuple_pattern(cause, &exp_found, diag);
|
||||||
self.suggest_accessing_field_where_appropriate(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_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);
|
self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ use rustc_middle::traits::{
|
||||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||||
StatementAsExpression,
|
StatementAsExpression,
|
||||||
};
|
};
|
||||||
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
|
use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
|
||||||
use rustc_span::{Span, sym};
|
use rustc_span::{Span, sym};
|
||||||
|
@ -20,7 +21,7 @@ use tracing::debug;
|
||||||
use crate::error_reporting::TypeErrCtxt;
|
use crate::error_reporting::TypeErrCtxt;
|
||||||
use crate::error_reporting::infer::hir::Path;
|
use crate::error_reporting::infer::hir::Path;
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
|
ConsiderAddingAwait, FnConsiderCasting, FnConsiderCastingBoth, FnItemsAreDistinct, FnUniqTypes,
|
||||||
FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
|
FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
|
||||||
SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
|
SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
|
||||||
};
|
};
|
||||||
|
@ -381,14 +382,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn suggest_function_pointers(
|
pub fn suggest_function_pointers_impl(
|
||||||
&self,
|
&self,
|
||||||
cause: &ObligationCause<'tcx>,
|
span: Option<Span>,
|
||||||
span: Span,
|
|
||||||
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
||||||
diag: &mut Diag<'_>,
|
diag: &mut Diag<'_>,
|
||||||
) {
|
) {
|
||||||
debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
|
|
||||||
let ty::error::ExpectedFound { expected, found } = exp_found;
|
let ty::error::ExpectedFound { expected, found } = exp_found;
|
||||||
let expected_inner = expected.peel_refs();
|
let expected_inner = expected.peel_refs();
|
||||||
let found_inner = found.peel_refs();
|
let found_inner = found.peel_refs();
|
||||||
|
@ -411,6 +410,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
return;
|
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()) {
|
let sugg = match (expected.is_ref(), found.is_ref()) {
|
||||||
(true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
|
(true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
|
||||||
(false, true) => FunctionPointerSuggestion::RemoveRef { 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 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() {
|
let sug = if found.is_ref() {
|
||||||
FunctionPointerSuggestion::CastBothRef {
|
FunctionPointerSuggestion::CastBothRef {
|
||||||
span,
|
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(
|
pub fn should_suggest_as_ref_kind(
|
||||||
&self,
|
&self,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
|
|
|
@ -1969,6 +1969,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
StringPart::highlighted(exp_found.found.to_string()),
|
StringPart::highlighted(exp_found.found.to_string()),
|
||||||
StringPart::normal("`"),
|
StringPart::normal("`"),
|
||||||
]);
|
]);
|
||||||
|
self.suggest_function_pointers_impl(None, &exp_found, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
|
@ -1496,6 +1496,12 @@ pub struct FnConsiderCasting {
|
||||||
pub casting: String,
|
pub casting: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[help(trait_selection_fn_consider_casting_both)]
|
||||||
|
pub struct FnConsiderCastingBoth<'a> {
|
||||||
|
pub sig: Binder<'a, FnSig<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub enum SuggestAccessingField<'a> {
|
pub enum SuggestAccessingField<'a> {
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
|
|
9
tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs
Normal file
9
tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs
Normal 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
|
||||||
|
}
|
59
tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr
Normal file
59
tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr
Normal 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`.
|
|
@ -10,6 +10,8 @@ LL | Self { map }
|
||||||
|
|
|
|
||||||
= note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
|
= 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::<'_>}>`
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue