When possible, suggest fn call

This commit is contained in:
Esteban Küber 2019-09-16 15:54:31 -07:00
parent 5976e0eecf
commit 2fbd6927a5
8 changed files with 64 additions and 32 deletions

View file

@ -81,6 +81,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.map(|obligation| FulfillmentError {
obligation: obligation.goal.clone(),
code: FulfillmentErrorCode::CodeAmbiguity,
points_at_arg_span: false,
})
.collect();
Err(errors)
@ -129,6 +130,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
code: FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented
),
points_at_arg_span: false,
}),
}
} else {
@ -142,6 +144,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
code: FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented
),
points_at_arg_span: false,
})
}
}

View file

@ -119,11 +119,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
// `error` occurring implies that `cond` occurs.
fn error_implies(&self,
cond: &ty::Predicate<'tcx>,
error: &ty::Predicate<'tcx>)
-> bool
{
fn error_implies(
&self,
cond: &ty::Predicate<'tcx>,
error: &ty::Predicate<'tcx>,
) -> bool {
if cond == error {
return true
}
@ -155,13 +155,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
false
}
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>,
body_id: Option<hir::BodyId>,
fallback_has_occurred: bool) {
fn report_fulfillment_error(
&self,
error: &FulfillmentError<'tcx>,
body_id: Option<hir::BodyId>,
fallback_has_occurred: bool,
) {
debug!("report_fulfillment_errors({:?})", error);
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref e) => {
self.report_selection_error(&error.obligation, e, fallback_has_occurred);
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
self.report_selection_error(
&error.obligation,
selection_error,
fallback_has_occurred,
error.points_at_arg_span,
);
}
FulfillmentErrorCode::CodeProjectionError(ref e) => {
self.report_projection_error(&error.obligation, e);
@ -170,19 +178,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.maybe_report_ambiguity(&error.obligation, body_id);
}
FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
self.report_mismatched_types(&error.obligation.cause,
expected_found.expected,
expected_found.found,
err.clone())
.emit();
self.report_mismatched_types(
&error.obligation.cause,
expected_found.expected,
expected_found.found,
err.clone(),
).emit();
}
}
}
fn report_projection_error(&self,
obligation: &PredicateObligation<'tcx>,
error: &MismatchedProjectionTypes<'tcx>)
{
fn report_projection_error(
&self,
obligation: &PredicateObligation<'tcx>,
error: &MismatchedProjectionTypes<'tcx>,
) {
let predicate =
self.resolve_vars_if_possible(&obligation.predicate);
@ -603,6 +613,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
fallback_has_occurred: bool,
points_at_arg: bool,
) {
let span = obligation.cause.span;
@ -690,7 +701,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
self.suggest_fn_call(&obligation, &mut err, &trait_ref);
self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
@ -963,6 +974,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
points_at_arg: bool,
) {
let self_ty = trait_ref.self_ty();
match self_ty.sty {
@ -991,15 +1003,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
..
})) = self.tcx.hir().get_if_local(def_id) {
let body = self.tcx.hir().body(*body_id);
err.help(&format!(
"use parentheses to call the function: `{}({})`",
let msg = "use parentheses to call the function";
let snippet = format!(
"{}({})",
ident,
body.params.iter()
.map(|arg| match &arg.pat.node {
hir::PatKind::Binding(_, _, ident, None)
if ident.name != kw::SelfLower => ident.to_string(),
_ => "_".to_string(),
}).collect::<Vec<_>>().join(", ")));
}).collect::<Vec<_>>().join(", "),
);
if points_at_arg {
err.span_suggestion(
obligation.cause.span,
msg,
snippet,
Applicability::HasPlaceholders,
);
} else {
err.help(&format!("{}: `{}`", msg, snippet));
}
}
}
_ => {}

View file

@ -484,7 +484,8 @@ EnumTypeFoldableImpl! {
pub struct FulfillmentError<'tcx> {
pub obligation: PredicateObligation<'tcx>,
pub code: FulfillmentErrorCode<'tcx>
pub code: FulfillmentErrorCode<'tcx>,
pub points_at_arg_span: bool,
}
#[derive(Clone)]
@ -1183,7 +1184,7 @@ impl<'tcx> FulfillmentError<'tcx> {
code: FulfillmentErrorCode<'tcx>)
-> FulfillmentError<'tcx>
{
FulfillmentError { obligation: obligation, code: code }
FulfillmentError { obligation: obligation, code: code, points_at_arg_span: false }
}
}

View file

@ -1999,6 +1999,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
),
&traits::SelectionError::Unimplemented,
false,
false,
);
}
}

View file

@ -617,7 +617,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Object safety violations or miscellaneous.
Err(err) => {
self.report_selection_error(&obligation, &err, false);
self.report_selection_error(&obligation, &err, false, false);
// Treat this like an obligation and follow through
// with the unsizing - the lack of a coercion should
// be silent, as it causes a type mismatch later.

View file

@ -3396,6 +3396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if referenced_in.len() == 1 {
error.obligation.cause.span = args[referenced_in[0]].span;
error.points_at_arg_span = true;
}
}
}

View file

@ -5,9 +5,10 @@ LL | fn bar(f: impl Future<Output=()>) {}
| --------------------------------- required by `bar`
...
LL | bar(foo);
| ^^^ the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
|
= help: use parentheses to call the function: `foo()`
| ^^^
| |
| the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
| help: use parentheses to call the function: `foo()`
error: aborting due to previous error

View file

@ -5,9 +5,10 @@ LL | fn bar(f: impl T<O=()>) {}
| ----------------------- required by `bar`
...
LL | bar(foo);
| ^^^ the trait `T` is not implemented for `fn() -> impl T {foo}`
|
= help: use parentheses to call the function: `foo()`
| ^^^
| |
| the trait `T` is not implemented for `fn() -> impl T {foo}`
| help: use parentheses to call the function: `foo()`
error: aborting due to previous error