Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6f1c20d

Browse files
committed
Suggest adding Fn bound when calling a generic parameter
1 parent f63685d commit 6f1c20d

File tree

5 files changed

+154
-6
lines changed

5 files changed

+154
-6
lines changed

‎compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use tracing::{debug, instrument};
2525
use super::method::MethodCallee;
2626
use super::method::probe::ProbeScope;
2727
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
28+
use crate::expr_use_visitor::TypeInformationCtxt;
2829
use crate::{errors, fluent_generated};
2930

3031
/// Checks that it is legal to call methods of the trait corresponding
@@ -122,7 +123,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
122123
);
123124
}
124125

125-
let guar = self.report_invalid_callee(call_expr, callee_expr, expr_ty, arg_exprs);
126+
let guar = self.report_invalid_callee(
127+
call_expr,
128+
callee_expr,
129+
expr_ty,
130+
arg_exprs,
131+
expected,
132+
);
126133
Ty::new_error(self.tcx, guar)
127134
}
128135

@@ -677,6 +684,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
677684
callee_expr: &'tcx hir::Expr<'tcx>,
678685
callee_ty: Ty<'tcx>,
679686
arg_exprs: &'tcx [hir::Expr<'tcx>],
687+
expected: Expectation<'tcx>,
680688
) -> ErrorGuaranteed {
681689
// Callee probe fails when APIT references errors, so suppress those
682690
// errors here.
@@ -806,6 +814,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
806814
err.span_label(def_span, "the callable type is defined here");
807815
}
808816
} else {
817+
// Suggest adding <Param>: Fn(...) [-> RetType]
818+
if callee_ty.has_non_region_param() {
819+
let arg_types: Vec<Ty<'tcx>> = arg_exprs
820+
.iter()
821+
.map(|arg| self.typeck_results.borrow().expr_ty(arg))
822+
.collect();
823+
let args_tuple = Ty::new_tup(self.tcx(), &arg_types);
824+
825+
let fn_def_id = self.tcx().require_lang_item(LangItem::Fn, callee_expr.span);
826+
let trait_ref =
827+
ty::TraitRef::new(self.tcx(), fn_def_id, [callee_ty, args_tuple]);
828+
829+
let trait_pred =
830+
ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive };
831+
832+
let associated_ty = expected
833+
.to_option(self)
834+
// We do not want to suggest e.g. `-> _`
835+
.filter(|ty| !ty.has_infer())
836+
.map(|ty| ("Output", ty));
837+
self.err_ctxt().suggest_restricting_param_bound(
838+
&mut err,
839+
ty::Binder::dummy(trait_pred),
840+
associated_ty,
841+
self.body_id,
842+
);
843+
}
809844
err.span_label(call_expr.span, "call expression requires function");
810845
}
811846
}

‎compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
388388
);
389389

390390
if let Some((name, term)) = associated_ty {
391-
// FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
392-
// That should be extracted into a helper function.
393-
if let Some(stripped) = constraint.strip_suffix('>') {
394-
constraint = format!("{stripped}, {name} = {term}>");
391+
if self.tcx.is_fn_trait(trait_pred.skip_binder().trait_ref.def_id) {
392+
constraint.push_str(&format!(" -> {term}"));
395393
} else {
396-
constraint.push_str(&format!("<{name} = {term}>"));
394+
// FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
395+
// That should be extracted into a helper function.
396+
if let Some(stripped) = constraint.strip_suffix('>') {
397+
constraint = format!("{stripped}, {name} = {term}>");
398+
} else {
399+
constraint.push_str(&format!("<{name} = {term}>"));
400+
}
397401
}
398402
}
399403

‎tests/ui/issues/issue-21701.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ LL | let y = t();
77
| ^--
88
| |
99
| call expression requires function
10+
|
11+
help: consider restricting type parameter `U` with trait `Fn`
12+
|
13+
LL | fn foo<U: Fn()>(t: U) {
14+
| ++++++
1015

1116
error[E0618]: expected function, found struct `Bar`
1217
--> $DIR/issue-21701.rs:9:13
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
fn return_type<T>(t: T) {
2+
let x: u32 = t(1);
3+
//~^ ERROR: expected function, found `T` [E0618]
4+
}
5+
6+
fn unknown_return_type<T>(t: T) {
7+
let x = t();
8+
//~^ ERROR: expected function, found `T` [E0618]
9+
}
10+
11+
fn nested_return_type<T>(t: Vec<T>) {
12+
t();
13+
//~^ ERROR: expected function, found `Vec<T>` [E0618]
14+
}
15+
16+
fn no_return_type<T>(t: T) {
17+
t(1, 2, true);
18+
//~^ ERROR: expected function, found `T` [E0618]
19+
}
20+
21+
fn existing_bound<T: Copy>(t: T) {
22+
t(false);
23+
//~^ ERROR: expected function, found `T` [E0618]
24+
}
25+
26+
fn main() {}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
error[E0618]: expected function, found `T`
2+
--> $DIR/suggest-call-on-generic-param.rs:2:18
3+
|
4+
LL | fn return_type<T>(t: T) {
5+
| - `t` has type `T`
6+
LL | let x: u32 = t(1);
7+
| ^---
8+
| |
9+
| call expression requires function
10+
|
11+
help: consider restricting type parameter `T` with trait `Fn`
12+
|
13+
LL | fn return_type<T: Fn(i32) -> u32>(t: T) {
14+
| ++++++++++++++++
15+
16+
error[E0618]: expected function, found `T`
17+
--> $DIR/suggest-call-on-generic-param.rs:7:13
18+
|
19+
LL | fn unknown_return_type<T>(t: T) {
20+
| - `t` has type `T`
21+
LL | let x = t();
22+
| ^--
23+
| |
24+
| call expression requires function
25+
|
26+
help: consider restricting type parameter `T` with trait `Fn`
27+
|
28+
LL | fn unknown_return_type<T: Fn()>(t: T) {
29+
| ++++++
30+
31+
error[E0618]: expected function, found `Vec<T>`
32+
--> $DIR/suggest-call-on-generic-param.rs:12:5
33+
|
34+
LL | fn nested_return_type<T>(t: Vec<T>) {
35+
| - `t` has type `Vec<T>`
36+
LL | t();
37+
| ^--
38+
| |
39+
| call expression requires function
40+
|
41+
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
42+
|
43+
LL | fn nested_return_type<T>(t: Vec<T>) where Vec<T>: Fn() {
44+
| ++++++++++++++++++
45+
46+
error[E0618]: expected function, found `T`
47+
--> $DIR/suggest-call-on-generic-param.rs:17:5
48+
|
49+
LL | fn no_return_type<T>(t: T) {
50+
| - `t` has type `T`
51+
LL | t(1, 2, true);
52+
| ^------------
53+
| |
54+
| call expression requires function
55+
|
56+
help: consider restricting type parameter `T` with trait `Fn`
57+
|
58+
LL | fn no_return_type<T: Fn(i32, i32, bool)>(t: T) {
59+
| ++++++++++++++++++++
60+
61+
error[E0618]: expected function, found `T`
62+
--> $DIR/suggest-call-on-generic-param.rs:22:5
63+
|
64+
LL | fn existing_bound<T: Copy>(t: T) {
65+
| - `t` has type `T`
66+
LL | t(false);
67+
| ^-------
68+
| |
69+
| call expression requires function
70+
|
71+
help: consider further restricting type parameter `T` with trait `Fn`
72+
|
73+
LL | fn existing_bound<T: Copy + Fn(bool)>(t: T) {
74+
| ++++++++++
75+
76+
error: aborting due to 5 previous errors
77+
78+
For more information about this error, try `rustc --explain E0618`.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /