Skip to content

Commit aa9bfde

Browse files
authored
Rollup merge of #101019 - compiler-errors:return-closure-suggestion, r=cjgillot
Suggest returning closure as `impl Fn` Fixes #100936
2 parents e63424d + 93b7d8d commit aa9bfde

File tree

6 files changed

+106
-24
lines changed

6 files changed

+106
-24
lines changed

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

+37
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,34 @@ pub trait PrettyPrinter<'tcx>:
15361536
}
15371537
Ok(self)
15381538
}
1539+
1540+
fn pretty_closure_as_impl(
1541+
mut self,
1542+
closure: ty::ClosureSubsts<'tcx>,
1543+
) -> Result<Self::Const, Self::Error> {
1544+
let sig = closure.sig();
1545+
let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn);
1546+
1547+
write!(self, "impl ")?;
1548+
self.wrap_binder(&sig, |sig, mut cx| {
1549+
define_scoped_cx!(cx);
1550+
1551+
p!(print(kind), "(");
1552+
for (i, arg) in sig.inputs()[0].tuple_fields().iter().enumerate() {
1553+
if i > 0 {
1554+
p!(", ");
1555+
}
1556+
p!(print(arg));
1557+
}
1558+
p!(")");
1559+
1560+
if !sig.output().is_unit() {
1561+
p!(" -> ", print(sig.output()));
1562+
}
1563+
1564+
Ok(cx)
1565+
})
1566+
}
15391567
}
15401568

15411569
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
@@ -2450,6 +2478,11 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> {
24502478
}
24512479
}
24522480

2481+
#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
2482+
pub struct PrintClosureAsImpl<'tcx> {
2483+
pub closure: ty::ClosureSubsts<'tcx>,
2484+
}
2485+
24532486
forward_display_to_print! {
24542487
ty::Region<'tcx>,
24552488
Ty<'tcx>,
@@ -2542,6 +2575,10 @@ define_print_and_forward_display! {
25422575
p!(print(self.0.trait_ref.print_only_trait_path()));
25432576
}
25442577

2578+
PrintClosureAsImpl<'tcx> {
2579+
p!(pretty_closure_as_impl(self.closure))
2580+
}
2581+
25452582
ty::ParamTy {
25462583
p!(write("{}", self.name))
25472584
}

compiler/rustc_middle/src/ty/sty.rs

+4
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ impl<'tcx> ClosureSubsts<'tcx> {
325325
_ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()),
326326
}
327327
}
328+
329+
pub fn print_as_impl_trait(self) -> ty::print::PrintClosureAsImpl<'tcx> {
330+
ty::print::PrintClosureAsImpl { closure: self }
331+
}
328332
}
329333

330334
/// Similar to `ClosureSubsts`; see the above documentation for more.

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

+23-22
Original file line numberDiff line numberDiff line change
@@ -506,30 +506,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
506506
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
507507
// Only suggest changing the return type for methods that
508508
// haven't set a return type at all (and aren't `fn main()` or an impl).
509-
match (
510-
&fn_decl.output,
511-
found.is_suggestable(self.tcx, false),
512-
can_suggest,
513-
expected.is_unit(),
514-
) {
515-
(&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
516-
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
517-
true
518-
}
519-
(&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
520-
// FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest
521-
// that.
522-
err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
523-
true
524-
}
525-
(&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
509+
match &fn_decl.output {
510+
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
526511
// `fn main()` must return `()`, do not suggest changing return type
527512
err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span });
528-
true
513+
return true;
529514
}
530-
// expectation was caused by something else, not the default return
531-
(&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
532-
(&hir::FnRetTy::Return(ref ty), _, _, _) => {
515+
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
516+
if found.is_suggestable(self.tcx, false) {
517+
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
518+
return true;
519+
} else if let ty::Closure(_, substs) = found.kind()
520+
// FIXME(compiler-errors): Get better at printing binders...
521+
&& let closure = substs.as_closure()
522+
&& closure.sig().is_suggestable(self.tcx, false)
523+
{
524+
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() });
525+
return true;
526+
} else {
527+
// FIXME: if `found` could be `impl Iterator` we should suggest that.
528+
err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
529+
return true
530+
}
531+
}
532+
&hir::FnRetTy::Return(ref ty) => {
533533
// Only point to return type if the expected type is the return type, as if they
534534
// are not, the expectation must have been caused by something else.
535535
debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
@@ -546,9 +546,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
546546
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
547547
return true;
548548
}
549-
false
550549
}
550+
_ => {}
551551
}
552+
false
552553
}
553554

554555
/// check whether the return type is a generic type with a trait bound

compiler/rustc_typeck/src/errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ pub struct AddressOfTemporaryTaken {
195195
}
196196

197197
#[derive(SessionSubdiagnostic)]
198-
pub enum AddReturnTypeSuggestion<'tcx> {
198+
pub enum AddReturnTypeSuggestion {
199199
#[suggestion(
200200
typeck::add_return_type_add,
201201
code = "-> {found} ",
@@ -204,7 +204,7 @@ pub enum AddReturnTypeSuggestion<'tcx> {
204204
Add {
205205
#[primary_span]
206206
span: Span,
207-
found: Ty<'tcx>,
207+
found: String,
208208
},
209209
#[suggestion(
210210
typeck::add_return_type_missing_here,
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fn foo() {
2+
//~^ HELP try adding a return type
3+
|x: &i32| 1i32
4+
//~^ ERROR mismatched types
5+
}
6+
7+
fn bar(i: impl Sized) {
8+
//~^ HELP a return type might be missing here
9+
|| i
10+
//~^ ERROR mismatched types
11+
}
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/return-closures.rs:3:5
3+
|
4+
LL | fn foo() {
5+
| - help: try adding a return type: `-> impl for<'r> Fn(&'r i32) -> i32`
6+
LL |
7+
LL | |x: &i32| 1i32
8+
| ^^^^^^^^^^^^^^ expected `()`, found closure
9+
|
10+
= note: expected unit type `()`
11+
found closure `[closure@$DIR/return-closures.rs:3:5: 3:14]`
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/return-closures.rs:9:5
15+
|
16+
LL | fn bar(i: impl Sized) {
17+
| - help: a return type might be missing here: `-> _`
18+
LL |
19+
LL | || i
20+
| ^^^^ expected `()`, found closure
21+
|
22+
= note: expected unit type `()`
23+
found closure `[closure@$DIR/return-closures.rs:9:5: 9:7]`
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)