diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-09-16 15:54:31 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-09-19 12:10:23 -0700 |
| commit | 2fbd6927a5116e856aa7085bbcab27e87271bb91 (patch) | |
| tree | 8c651719a7b7ac196e4b2731424b41311d84297a /src | |
| parent | 5976e0eecf8e3f3a9d37f16a902cbb70a23d09c7 (diff) | |
| download | rust-2fbd6927a5116e856aa7085bbcab27e87271bb91.tar.gz rust-2fbd6927a5116e856aa7085bbcab27e87271bb91.zip | |
When possible, suggest fn call
Diffstat (limited to 'src')
8 files changed, 64 insertions, 32 deletions
diff --git a/src/librustc/traits/chalk_fulfill.rs b/src/librustc/traits/chalk_fulfill.rs index 0c7c94b684a..a7e1f2a6a73 100644 --- a/src/librustc/traits/chalk_fulfill.rs +++ b/src/librustc/traits/chalk_fulfill.rs @@ -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, }) } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 03cc00d87e3..e52451b2fdc 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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)); + } } } _ => {} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index d2683090add..b7db7c25206 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -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 } } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 62bff3421a0..6a764b19c4d 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1999,6 +1999,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ), &traits::SelectionError::Unimplemented, false, + false, ); } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f2e1a6e29d6..ee4f0a868c1 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -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. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c98f3373d39..df9955d6ba0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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; } } } diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 4df639b55e5..6bb65338996 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -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 diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index f51f1a8215c..59726c82c23 100644 --- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -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 |
