Skip to content

Commit 910b60f

Browse files
authored
Rollup merge of rust-lang#98280 - compiler-errors:better-call-closure-on-type-err, r=estebank
Improve suggestion for calling fn-like expr on type mismatch 1.) Suggest calling values of with RPIT types (and probably TAIT) when we expect `Ty` and have `impl Fn() -> Ty` 2.) Suggest calling closures even when they're not assigned to a local variable first 3.) Drive-by fix of a pretty-printing bug (`impl Fn()-> Ty` => `impl Fn() -> Ty`) r? ``@estebank``
2 parents abd04ee + d15fed7 commit 910b60f

File tree

11 files changed

+143
-125
lines changed

11 files changed

+143
-125
lines changed

compiler/rustc_middle/src/ty/print/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ pub trait PrettyPrinter<'tcx>:
856856
p!(")");
857857
if let Term::Ty(ty) = return_ty.skip_binder() {
858858
if !ty.is_unit() {
859-
p!("-> ", print(return_ty));
859+
p!(" -> ", print(return_ty));
860860
}
861861
}
862862
p!(write("{}", if paren_needed { ")" } else { "" }));

compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs

+76-113
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ use rustc_hir as hir;
88
use rustc_hir::def::{CtorOf, DefKind};
99
use rustc_hir::lang_items::LangItem;
1010
use rustc_hir::{
11-
Expr, ExprKind, GenericBound, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind,
12-
WherePredicate,
11+
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
1312
};
1413
use rustc_infer::infer::{self, TyCtxtInferExt};
1514
use rustc_infer::traits;
1615
use rustc_middle::lint::in_external_macro;
1716
use rustc_middle::ty::subst::GenericArgKind;
18-
use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
19-
use rustc_span::symbol::{kw, sym};
17+
use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
18+
use rustc_span::symbol::sym;
2019
use rustc_span::Span;
2120
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
2221

@@ -78,124 +77,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7877
expected: Ty<'tcx>,
7978
found: Ty<'tcx>,
8079
) -> bool {
81-
let hir = self.tcx.hir();
82-
let (def_id, sig) = match *found.kind() {
83-
ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
84-
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
80+
let (def_id, output, inputs) = match *found.kind() {
81+
ty::FnDef(def_id, _) => {
82+
let fn_sig = found.fn_sig(self.tcx);
83+
(def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len())
84+
}
85+
ty::Closure(def_id, substs) => {
86+
let fn_sig = substs.as_closure().sig();
87+
(def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len() - 1)
88+
}
89+
ty::Opaque(def_id, substs) => {
90+
let sig = self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
91+
if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
92+
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
93+
// args tuple will always be substs[1]
94+
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
95+
{
96+
Some((
97+
pred.kind().rebind(proj.term.ty().unwrap()),
98+
args.len(),
99+
))
100+
} else {
101+
None
102+
}
103+
});
104+
if let Some((output, inputs)) = sig {
105+
(def_id, output, inputs)
106+
} else {
107+
return false;
108+
}
109+
}
85110
_ => return false,
86111
};
87112

88-
let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig);
89-
let sig = self.normalize_associated_types_in(expr.span, sig);
90-
if self.can_coerce(sig.output(), expected) {
91-
let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
92-
(String::new(), Applicability::MachineApplicable)
93-
} else {
94-
("...".to_string(), Applicability::HasPlaceholders)
113+
let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
114+
let output = self.normalize_associated_types_in(expr.span, output);
115+
if !output.is_ty_var() && self.can_coerce(output, expected) {
116+
let (sugg_call, mut applicability) = match inputs {
117+
0 => ("".to_string(), Applicability::MachineApplicable),
118+
1..=4 => (
119+
(0..inputs).map(|_| "_").collect::<Vec<_>>().join(", "),
120+
Applicability::MachineApplicable,
121+
),
122+
_ => ("...".to_string(), Applicability::HasPlaceholders),
95123
};
96-
let mut msg = "call this function";
97-
match hir.get_if_local(def_id) {
98-
Some(
99-
Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
100-
| Node::ImplItem(hir::ImplItem {
101-
kind: hir::ImplItemKind::Fn(_, body_id), ..
102-
})
103-
| Node::TraitItem(hir::TraitItem {
104-
kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
105-
..
106-
}),
107-
) => {
108-
let body = hir.body(*body_id);
109-
sugg_call = body
110-
.params
111-
.iter()
112-
.map(|param| match &param.pat.kind {
113-
hir::PatKind::Binding(_, _, ident, None)
114-
if ident.name != kw::SelfLower =>
115-
{
116-
ident.to_string()
117-
}
118-
_ => "_".to_string(),
119-
})
120-
.collect::<Vec<_>>()
121-
.join(", ");
122-
}
123-
Some(Node::Expr(hir::Expr {
124-
kind: ExprKind::Closure { body: body_id, .. },
125-
span: full_closure_span,
126-
..
127-
})) => {
128-
if *full_closure_span == expr.span {
129-
return false;
130-
}
131-
msg = "call this closure";
132-
let body = hir.body(*body_id);
133-
sugg_call = body
134-
.params
135-
.iter()
136-
.map(|param| match &param.pat.kind {
137-
hir::PatKind::Binding(_, _, ident, None)
138-
if ident.name != kw::SelfLower =>
139-
{
140-
ident.to_string()
141-
}
142-
_ => "_".to_string(),
143-
})
144-
.collect::<Vec<_>>()
145-
.join(", ");
146-
}
147-
Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
148-
sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
149-
match def_id.as_local().map(|def_id| self.tcx.def_kind(def_id)) {
150-
Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
151-
msg = "instantiate this tuple variant";
152-
}
153-
Some(DefKind::Ctor(CtorOf::Struct, _)) => {
154-
msg = "instantiate this tuple struct";
155-
}
156-
_ => {}
157-
}
124+
125+
let msg = match self.tcx.def_kind(def_id) {
126+
DefKind::Fn => "call this function",
127+
DefKind::Closure | DefKind::OpaqueTy => "call this closure",
128+
DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct",
129+
DefKind::Ctor(CtorOf::Variant, _) => "instantiate this tuple variant",
130+
_ => "call this function",
131+
};
132+
133+
let sugg = match expr.kind {
134+
hir::ExprKind::Call(..)
135+
| hir::ExprKind::Path(..)
136+
| hir::ExprKind::Index(..)
137+
| hir::ExprKind::Lit(..) => {
138+
vec![(expr.span.shrink_to_hi(), format!("({sugg_call})"))]
158139
}
159-
Some(Node::ForeignItem(hir::ForeignItem {
160-
kind: hir::ForeignItemKind::Fn(_, idents, _),
161-
..
162-
})) => {
163-
sugg_call = idents
164-
.iter()
165-
.map(|ident| {
166-
if ident.name != kw::SelfLower {
167-
ident.to_string()
168-
} else {
169-
"_".to_string()
170-
}
171-
})
172-
.collect::<Vec<_>>()
173-
.join(", ")
140+
hir::ExprKind::Closure { .. } => {
141+
// Might be `{ expr } || { bool }`
142+
applicability = Applicability::MaybeIncorrect;
143+
vec![
144+
(expr.span.shrink_to_lo(), "(".to_string()),
145+
(expr.span.shrink_to_hi(), format!(")({sugg_call})")),
146+
]
174147
}
175-
Some(Node::TraitItem(hir::TraitItem {
176-
kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
177-
..
178-
})) => {
179-
sugg_call = idents
180-
.iter()
181-
.map(|ident| {
182-
if ident.name != kw::SelfLower {
183-
ident.to_string()
184-
} else {
185-
"_".to_string()
186-
}
187-
})
188-
.collect::<Vec<_>>()
189-
.join(", ")
148+
_ => {
149+
vec![
150+
(expr.span.shrink_to_lo(), "(".to_string()),
151+
(expr.span.shrink_to_hi(), format!(")({sugg_call})")),
152+
]
190153
}
191-
_ => {}
192-
}
193-
err.span_suggestion_verbose(
194-
expr.span.shrink_to_hi(),
195-
&format!("use parentheses to {}", msg),
196-
format!("({})", sugg_call),
154+
};
155+
156+
err.multipart_suggestion_verbose(
157+
format!("use parentheses to {msg}"),
158+
sugg,
197159
applicability,
198160
);
161+
199162
return true;
200163
}
201164
false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn whatever() -> i32 {
2+
opaque()
3+
//~^ ERROR mismatched types
4+
}
5+
6+
fn opaque() -> impl Fn() -> i32 {
7+
|| 0
8+
}
9+
10+
fn main() {
11+
let _ = whatever();
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/suggest-calling-rpit-closure.rs:2:5
3+
|
4+
LL | fn whatever() -> i32 {
5+
| --- expected `i32` because of return type
6+
LL | opaque()
7+
| ^^^^^^^^ expected `i32`, found opaque type
8+
...
9+
LL | fn opaque() -> impl Fn() -> i32 {
10+
| ---------------- the found opaque type
11+
|
12+
= note: expected type `i32`
13+
found opaque type `impl Fn() -> i32`
14+
help: use parentheses to call this closure
15+
|
16+
LL | opaque()()
17+
| ++
18+
19+
error: aborting due to previous error
20+
21+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/parser/expr-as-stmt.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ LL | { true } || { true }
201201
|
202202
= note: expected type `bool`
203203
found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:25]`
204+
help: use parentheses to call this closure
205+
|
206+
LL | { true } (|| { true })()
207+
| + +++
204208
help: parentheses are required to parse this as an expression
205209
|
206210
LL | ({ true }) || { true }

src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ LL | | }.hi() {
2525
|
2626
= note: expected type `bool`
2727
found closure `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 14:11]`
28+
help: use parentheses to call this closure
29+
|
30+
LL ~ while (|| Foo {
31+
LL | x: 3
32+
LL ~ }.hi())() {
33+
|
2834

2935
error: aborting due to 2 previous errors
3036

src/test/ui/reify-intrinsic.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr
88
|
99
= note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
1010
found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
11-
help: use parentheses to call this function
12-
|
13-
LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute(...);
14-
| +++++
1511

1612
error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
1713
--> $DIR/reify-intrinsic.rs:11:13

src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,10 @@ LL | if let Range { start: F, end } = F..|| true {}
11181118
|
11191119
= note: expected type `bool`
11201120
found closure `[closure@$DIR/disallowed-positions.rs:136:41: 136:48]`
1121+
help: use parentheses to call this closure
1122+
|
1123+
LL | if let Range { start: F, end } = F..(|| true)() {}
1124+
| + +++
11211125

11221126
error[E0308]: mismatched types
11231127
--> $DIR/disallowed-positions.rs:136:8
@@ -1314,6 +1318,10 @@ LL | while let Range { start: F, end } = F..|| true {}
13141318
|
13151319
= note: expected type `bool`
13161320
found closure `[closure@$DIR/disallowed-positions.rs:200:44: 200:51]`
1321+
help: use parentheses to call this closure
1322+
|
1323+
LL | while let Range { start: F, end } = F..(|| true)() {}
1324+
| + +++
13171325

13181326
error[E0308]: mismatched types
13191327
--> $DIR/disallowed-positions.rs:200:11

src/test/ui/span/move-closure.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ LL | let x: () = move || ();
88
|
99
= note: expected unit type `()`
1010
found closure `[closure@$DIR/move-closure.rs:5:17: 5:27]`
11+
help: use parentheses to call this closure
12+
|
13+
LL | let x: () = (move || ())();
14+
| + +++
1115

1216
error: aborting due to previous error
1317

src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr

+7-7
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ LL | let _: usize = foo;
3333
found fn item `fn(usize, usize) -> usize {foo}`
3434
help: use parentheses to call this function
3535
|
36-
LL | let _: usize = foo(a, b);
36+
LL | let _: usize = foo(_, _);
3737
| ++++++
3838

3939
error[E0308]: mismatched types
@@ -105,7 +105,7 @@ LL | let _: usize = T::baz;
105105
found fn item `fn(usize, usize) -> usize {<_ as T>::baz}`
106106
help: use parentheses to call this function
107107
|
108-
LL | let _: usize = T::baz(x, y);
108+
LL | let _: usize = T::baz(_, _);
109109
| ++++++
110110

111111
error[E0308]: mismatched types
@@ -123,7 +123,7 @@ LL | let _: usize = T::bat;
123123
found fn item `fn(usize) -> usize {<_ as T>::bat}`
124124
help: use parentheses to call this function
125125
|
126-
LL | let _: usize = T::bat(x);
126+
LL | let _: usize = T::bat(_);
127127
| +++
128128

129129
error[E0308]: mismatched types
@@ -159,7 +159,7 @@ LL | let _: usize = X::baz;
159159
found fn item `fn(usize, usize) -> usize {<X as T>::baz}`
160160
help: use parentheses to call this function
161161
|
162-
LL | let _: usize = X::baz(x, y);
162+
LL | let _: usize = X::baz(_, _);
163163
| ++++++
164164

165165
error[E0308]: mismatched types
@@ -177,7 +177,7 @@ LL | let _: usize = X::bat;
177177
found fn item `fn(usize) -> usize {<X as T>::bat}`
178178
help: use parentheses to call this function
179179
|
180-
LL | let _: usize = X::bat(x);
180+
LL | let _: usize = X::bat(_);
181181
| +++
182182

183183
error[E0308]: mismatched types
@@ -195,7 +195,7 @@ LL | let _: usize = X::bax;
195195
found fn item `fn(usize) -> usize {<X as T>::bax}`
196196
help: use parentheses to call this function
197197
|
198-
LL | let _: usize = X::bax(x);
198+
LL | let _: usize = X::bax(_);
199199
| +++
200200

201201
error[E0308]: mismatched types
@@ -213,7 +213,7 @@ LL | let _: usize = X::bach;
213213
found fn item `fn(usize) -> usize {<X as T>::bach}`
214214
help: use parentheses to call this function
215215
|
216-
LL | let _: usize = X::bach(x);
216+
LL | let _: usize = X::bach(_);
217217
| +++
218218

219219
error[E0308]: mismatched types

0 commit comments

Comments
 (0)