Skip to content

Commit 14af2bc

Browse files
Rollup merge of rust-lang#133382 - mu001999-contrib:diag/fnitem, r=lcnr
Suggest considering casting fn item as fn pointer in more cases Fixes rust-lang#132648
2 parents a1d7676 + 4203627 commit 14af2bc

File tree

8 files changed

+114
-6
lines changed

8 files changed

+114
-6
lines changed

Diff for: compiler/rustc_trait_selection/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime r
165165
166166
trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
167167
168+
trait_selection_fn_consider_casting_both = consider casting both fn items to fn pointers using `as {$sig}`
169+
168170
trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same
169171
trait_selection_fps_cast = consider casting to a fn pointer
170172
trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`

Diff for: compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1844,7 +1844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
18441844
self.suggest_tuple_pattern(cause, &exp_found, diag);
18451845
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
18461846
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
1847-
self.suggest_function_pointers(cause, span, &exp_found, diag);
1847+
self.suggest_function_pointers(cause, span, &exp_found, terr, diag);
18481848
self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
18491849
}
18501850
}

Diff for: compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_middle::traits::{
1212
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
1313
StatementAsExpression,
1414
};
15+
use rustc_middle::ty::error::TypeError;
1516
use rustc_middle::ty::print::with_no_trimmed_paths;
1617
use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
1718
use rustc_span::{Span, sym};
@@ -20,7 +21,7 @@ use tracing::debug;
2021
use crate::error_reporting::TypeErrCtxt;
2122
use crate::error_reporting::infer::hir::Path;
2223
use crate::errors::{
23-
ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
24+
ConsiderAddingAwait, FnConsiderCasting, FnConsiderCastingBoth, FnItemsAreDistinct, FnUniqTypes,
2425
FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
2526
SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
2627
};
@@ -381,14 +382,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
381382
}
382383
}
383384

384-
pub(super) fn suggest_function_pointers(
385+
pub fn suggest_function_pointers_impl(
385386
&self,
386-
cause: &ObligationCause<'tcx>,
387-
span: Span,
387+
span: Option<Span>,
388388
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
389389
diag: &mut Diag<'_>,
390390
) {
391-
debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
392391
let ty::error::ExpectedFound { expected, found } = exp_found;
393392
let expected_inner = expected.peel_refs();
394393
let found_inner = found.peel_refs();
@@ -411,6 +410,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
411410
return;
412411
}
413412

413+
let Some(span) = span else {
414+
let casting = format!("{fn_name} as {sig}");
415+
diag.subdiagnostic(FnItemsAreDistinct);
416+
diag.subdiagnostic(FnConsiderCasting { casting });
417+
return;
418+
};
419+
414420
let sugg = match (expected.is_ref(), found.is_ref()) {
415421
(true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
416422
(false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
@@ -445,6 +451,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
445451
}
446452

447453
let fn_name = self.tcx.def_path_str_with_args(*did2, args2);
454+
455+
let Some(span) = span else {
456+
diag.subdiagnostic(FnConsiderCastingBoth { sig: *expected_sig });
457+
return;
458+
};
459+
448460
let sug = if found.is_ref() {
449461
FunctionPointerSuggestion::CastBothRef {
450462
span,
@@ -488,6 +500,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
488500
};
489501
}
490502

503+
pub(super) fn suggest_function_pointers(
504+
&self,
505+
cause: &ObligationCause<'tcx>,
506+
span: Span,
507+
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
508+
terr: TypeError<'tcx>,
509+
diag: &mut Diag<'_>,
510+
) {
511+
debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
512+
513+
if exp_found.expected.peel_refs().is_fn() && exp_found.found.peel_refs().is_fn() {
514+
self.suggest_function_pointers_impl(Some(span), exp_found, diag);
515+
} else if let TypeError::Sorts(exp_found) = terr {
516+
self.suggest_function_pointers_impl(None, &exp_found, diag);
517+
}
518+
}
519+
491520
pub fn should_suggest_as_ref_kind(
492521
&self,
493522
expected: Ty<'tcx>,

Diff for: compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19691969
StringPart::highlighted(exp_found.found.to_string()),
19701970
StringPart::normal("`"),
19711971
]);
1972+
self.suggest_function_pointers_impl(None, &exp_found, err);
19721973
}
19731974

19741975
true

Diff for: compiler/rustc_trait_selection/src/errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,12 @@ pub struct FnConsiderCasting {
14961496
pub casting: String,
14971497
}
14981498

1499+
#[derive(Subdiagnostic)]
1500+
#[help(trait_selection_fn_consider_casting_both)]
1501+
pub struct FnConsiderCastingBoth<'a> {
1502+
pub sig: Binder<'a, FnSig<'a>>,
1503+
}
1504+
14991505
#[derive(Subdiagnostic)]
15001506
pub enum SuggestAccessingField<'a> {
15011507
#[suggestion(
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ edition: 2021
2+
3+
fn foo() {}
4+
5+
fn main() {
6+
let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect(); //~ ERROR
7+
let _: Vec<fn()> = [foo].into_iter().collect(); //~ ERROR
8+
let _: Vec<fn()> = Vec::from([foo]); //~ ERROR
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error[E0277]: a value of type `Vec<(&str, fn())>` cannot be built from an iterator over elements of type `(&str, fn() {foo})`
2+
--> $DIR/casting-fn-item-to-fn-pointer.rs:6:59
3+
|
4+
LL | let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
5+
| ^^^^^^^ value of type `Vec<(&str, fn())>` cannot be built from `std::iter::Iterator<Item=(&str, fn() {foo})>`
6+
|
7+
= help: the trait `FromIterator<(&_, fn() {foo})>` is not implemented for `Vec<(&str, fn())>`
8+
but trait `FromIterator<(&_, fn())>` is implemented for it
9+
= help: for that trait implementation, expected `fn()`, found `fn() {foo}`
10+
= note: fn items are distinct from fn pointers
11+
= help: consider casting the fn item to a fn pointer: `foo as fn()`
12+
note: the method call chain might not have had the expected associated types
13+
--> $DIR/casting-fn-item-to-fn-pointer.rs:6:47
14+
|
15+
LL | let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
16+
| -------------- ^^^^^^^^^^^ `Iterator::Item` is `(&str, fn() {foo})` here
17+
| |
18+
| this expression has type `[(&str, fn() {foo}); 1]`
19+
note: required by a bound in `collect`
20+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
21+
22+
error[E0277]: a value of type `Vec<fn()>` cannot be built from an iterator over elements of type `fn() {foo}`
23+
--> $DIR/casting-fn-item-to-fn-pointer.rs:7:42
24+
|
25+
LL | let _: Vec<fn()> = [foo].into_iter().collect();
26+
| ^^^^^^^ value of type `Vec<fn()>` cannot be built from `std::iter::Iterator<Item=fn() {foo}>`
27+
|
28+
= help: the trait `FromIterator<fn() {foo}>` is not implemented for `Vec<fn()>`
29+
but trait `FromIterator<fn()>` is implemented for it
30+
= help: for that trait implementation, expected `fn()`, found `fn() {foo}`
31+
= note: fn items are distinct from fn pointers
32+
= help: consider casting the fn item to a fn pointer: `foo as fn()`
33+
note: the method call chain might not have had the expected associated types
34+
--> $DIR/casting-fn-item-to-fn-pointer.rs:7:30
35+
|
36+
LL | let _: Vec<fn()> = [foo].into_iter().collect();
37+
| ----- ^^^^^^^^^^^ `Iterator::Item` is `fn() {foo}` here
38+
| |
39+
| this expression has type `[fn() {foo}; 1]`
40+
note: required by a bound in `collect`
41+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
42+
43+
error[E0308]: mismatched types
44+
--> $DIR/casting-fn-item-to-fn-pointer.rs:8:24
45+
|
46+
LL | let _: Vec<fn()> = Vec::from([foo]);
47+
| --------- ^^^^^^^^^^^^^^^^ expected `Vec<fn()>`, found `Vec<fn() {foo}>`
48+
| |
49+
| expected due to this
50+
|
51+
= note: expected struct `Vec<fn()>`
52+
found struct `Vec<fn() {foo}>`
53+
= note: fn items are distinct from fn pointers
54+
= help: consider casting the fn item to a fn pointer: `foo as fn()`
55+
56+
error: aborting due to 3 previous errors
57+
58+
Some errors have detailed explanations: E0277, E0308.
59+
For more information about an error, try `rustc --explain E0277`.

Diff for: tests/ui/typeck/issue-107775.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ LL | Self { map }
1010
|
1111
= note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
1212
found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
13+
= note: fn items are distinct from fn pointers
14+
= 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)>>`
1315

1416
error: aborting due to 1 previous error
1517

0 commit comments

Comments
 (0)