Suggest returning closure as impl Fn
This commit is contained in:
parent
7480389611
commit
448c6a4db7
6 changed files with 86 additions and 24 deletions
|
@ -1536,6 +1536,34 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pretty_closure_as_impl(
|
||||||
|
mut self,
|
||||||
|
closure: ty::ClosureSubsts<'tcx>,
|
||||||
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
let sig = closure.sig();
|
||||||
|
let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn);
|
||||||
|
|
||||||
|
write!(self, "impl ")?;
|
||||||
|
self.wrap_binder(&sig, |sig, mut cx| {
|
||||||
|
define_scoped_cx!(cx);
|
||||||
|
|
||||||
|
p!(print(kind), "(");
|
||||||
|
for (i, arg) in sig.inputs()[0].tuple_fields().iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
p!(", ");
|
||||||
|
}
|
||||||
|
p!(print(arg));
|
||||||
|
}
|
||||||
|
p!(")");
|
||||||
|
|
||||||
|
if !sig.output().is_unit() {
|
||||||
|
p!(" -> ", print(sig.output()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cx)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
|
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
|
||||||
|
@ -2450,6 +2478,11 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
|
||||||
|
pub struct PrintClosureAsImpl<'tcx> {
|
||||||
|
pub closure: ty::ClosureSubsts<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
forward_display_to_print! {
|
forward_display_to_print! {
|
||||||
ty::Region<'tcx>,
|
ty::Region<'tcx>,
|
||||||
Ty<'tcx>,
|
Ty<'tcx>,
|
||||||
|
@ -2542,6 +2575,10 @@ define_print_and_forward_display! {
|
||||||
p!(print(self.0.trait_ref.print_only_trait_path()));
|
p!(print(self.0.trait_ref.print_only_trait_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintClosureAsImpl<'tcx> {
|
||||||
|
p!(pretty_closure_as_impl(self.closure))
|
||||||
|
}
|
||||||
|
|
||||||
ty::ParamTy {
|
ty::ParamTy {
|
||||||
p!(write("{}", self.name))
|
p!(write("{}", self.name))
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,6 +325,10 @@ impl<'tcx> ClosureSubsts<'tcx> {
|
||||||
_ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()),
|
_ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn print_as_impl_trait(self) -> ty::print::PrintClosureAsImpl<'tcx> {
|
||||||
|
ty::print::PrintClosureAsImpl { closure: self }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to `ClosureSubsts`; see the above documentation for more.
|
/// Similar to `ClosureSubsts`; see the above documentation for more.
|
||||||
|
|
|
@ -506,30 +506,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||||
// Only suggest changing the return type for methods that
|
// Only suggest changing the return type for methods that
|
||||||
// haven't set a return type at all (and aren't `fn main()` or an impl).
|
// haven't set a return type at all (and aren't `fn main()` or an impl).
|
||||||
match (
|
match &fn_decl.output {
|
||||||
&fn_decl.output,
|
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
|
||||||
found.is_suggestable(self.tcx, false),
|
|
||||||
can_suggest,
|
|
||||||
expected.is_unit(),
|
|
||||||
) {
|
|
||||||
(&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
|
|
||||||
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
|
|
||||||
true
|
|
||||||
}
|
|
||||||
(&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
|
|
||||||
// FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest
|
|
||||||
// that.
|
|
||||||
err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
|
|
||||||
true
|
|
||||||
}
|
|
||||||
(&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
|
|
||||||
// `fn main()` must return `()`, do not suggest changing return type
|
// `fn main()` must return `()`, do not suggest changing return type
|
||||||
err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span });
|
err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span });
|
||||||
true
|
return true;
|
||||||
}
|
}
|
||||||
// expectation was caused by something else, not the default return
|
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
|
||||||
(&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
|
if found.is_suggestable(self.tcx, false) {
|
||||||
(&hir::FnRetTy::Return(ref ty), _, _, _) => {
|
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
|
||||||
|
return true;
|
||||||
|
} else if let ty::Closure(_, substs) = found.kind()
|
||||||
|
// FIXME(compiler-errors): Get better at printing binders...
|
||||||
|
&& let closure = substs.as_closure()
|
||||||
|
&& closure.sig().is_suggestable(self.tcx, false)
|
||||||
|
{
|
||||||
|
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() });
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// FIXME: if `found` could be `impl Iterator` we should suggest that.
|
||||||
|
err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&hir::FnRetTy::Return(ref ty) => {
|
||||||
// Only point to return type if the expected type is the return type, as if they
|
// Only point to return type if the expected type is the return type, as if they
|
||||||
// are not, the expectation must have been caused by something else.
|
// are not, the expectation must have been caused by something else.
|
||||||
debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
|
debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
|
||||||
|
@ -546,10 +546,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
|
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// check whether the return type is a generic type with a trait bound
|
/// check whether the return type is a generic type with a trait bound
|
||||||
/// only suggest this if the generic param is not present in the arguments
|
/// only suggest this if the generic param is not present in the arguments
|
||||||
|
|
|
@ -195,7 +195,7 @@ pub struct AddressOfTemporaryTaken {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SessionSubdiagnostic)]
|
#[derive(SessionSubdiagnostic)]
|
||||||
pub enum AddReturnTypeSuggestion<'tcx> {
|
pub enum AddReturnTypeSuggestion {
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
typeck::add_return_type_add,
|
typeck::add_return_type_add,
|
||||||
code = "-> {found} ",
|
code = "-> {found} ",
|
||||||
|
@ -204,7 +204,7 @@ pub enum AddReturnTypeSuggestion<'tcx> {
|
||||||
Add {
|
Add {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
found: Ty<'tcx>,
|
found: String,
|
||||||
},
|
},
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
typeck::add_return_type_missing_here,
|
typeck::add_return_type_missing_here,
|
||||||
|
|
6
src/test/ui/suggestions/return-closures.rs
Normal file
6
src/test/ui/suggestions/return-closures.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fn foo() {
|
||||||
|
|x: &i32| 1i32
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
src/test/ui/suggestions/return-closures.stderr
Normal file
14
src/test/ui/suggestions/return-closures.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/return-closures.rs:2:5
|
||||||
|
|
|
||||||
|
LL | fn foo() {
|
||||||
|
| - help: try adding a return type: `-> impl for<'r> Fn(&'r i32) -> i32`
|
||||||
|
LL | |x: &i32| 1i32
|
||||||
|
| ^^^^^^^^^^^^^^ expected `()`, found closure
|
||||||
|
|
|
||||||
|
= note: expected unit type `()`
|
||||||
|
found closure `[closure@$DIR/return-closures.rs:2:5: 2:14]`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Reference in a new issue