suggest await before try when performing trait selection

This commit is contained in:
csmoe 2020-05-10 20:07:42 +08:00
parent 114cd006f5
commit 627f473dd4
4 changed files with 92 additions and 10 deletions

View File

@ -25,7 +25,7 @@
)
)]
#[doc(alias = "?")]
#[cfg_attr(not(bootstrap), lang = "try_trait")]
#[cfg_attr(not(bootstrap), lang = "try_trait")]
pub trait Try {
/// The type of this value when viewed as successful.
#[unstable(feature = "try_trait", issue = "42327")]

View File

@ -400,6 +400,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
self.note_version_mismatch(&mut err, &trait_ref);
//self.sugggest_await_before_try(&mut err, &obligation, &trait_ref);
debug!(
"suggest_await_befor_try: trait_predicate={:?} obligation={:?}, trait_ref={:?}",
trait_predicate, obligation, trait_ref
);
self.suggest_await_befor_try(
&mut err,
&obligation,
trait_ref.self_ty(),
span,
);
if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
err.emit();
return;

View File

@ -1,8 +1,10 @@
use super::{
EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
SelectionContext,
};
use crate::infer::InferCtxt;
use crate::traits::normalize_projection_type;
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
use rustc_hir as hir;
@ -150,6 +152,15 @@ pub trait InferCtxtExt<'tcx> {
T: fmt::Display;
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
/// Suggest to await before try: future? => future.await?
fn suggest_await_befor_try(
&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>,
ty: Ty<'tcx>,
span: Span,
);
}
fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
@ -1765,6 +1776,75 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
suggested_limit, self.tcx.crate_name,
));
}
fn suggest_await_befor_try(
&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>,
ty: Ty<'tcx>,
span: Span,
) {
debug!("suggest_await_befor_try: obligation={:?}, span={:?}", obligation, span);
let body_hir_id = obligation.cause.body_id;
let item_id = self.tcx.hir().get_parent_node(body_hir_id);
if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) {
let body = self.tcx.hir().body(body_id);
if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
// Check for `Future` implementations by constructing a predicate to
// prove: `<T as Future>::Output == U`
let future_trait = self.tcx.lang_items().future_trait().unwrap();
let item_def_id = self
.tcx
.associated_items(future_trait)
.in_definition_order()
.next()
.unwrap()
.def_id;
// `<T as Future>::Output`
let projection_ty = ty::ProjectionTy {
// `T`
substs: self
.tcx
.mk_substs_trait(ty, self.fresh_substs_for_item(span, item_def_id)),
// `Future::Output`
item_def_id,
};
let cause = ObligationCause::misc(span, body_hir_id);
let mut selcx = SelectionContext::new(self);
let mut obligations = vec![];
let normalized_ty = normalize_projection_type(
&mut selcx,
obligation.param_env,
projection_ty,
obligation.cause.clone(),
0,
&mut obligations,
);
debug!("suggest_await_befor_try: normalized_projection_type {:?}", normalized_ty);
let try_trait_ref_id = self.tcx.lang_items().try_trait().unwrap();
if let Some(try_trait_ref) = self.tcx.impl_trait_ref(try_trait_ref_id) {
let try_predicate = try_trait_ref.without_const().to_predicate();
let try_obligation =
Obligation::new(cause, obligation.param_env, try_predicate);
debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation);
if self.predicate_may_hold(&try_obligation) {
debug!("try_obligation holds");
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
err.span_suggestion(
span,
"consider using `.await` here",
format!("{}.await", snippet),
Applicability::MaybeIncorrect,
);
}
}
}
}
}
}
}
/// Collect all the returned expressions within the input expression.

View File

@ -5317,15 +5317,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_def_id,
};
let cause = traits::ObligationCause::misc(sp, self.body_id);
let normalized_ty = self.fulfillment_cx.borrow_mut().normalize_projection_type(
&self.infcx,
self.param_env,
projection_ty,
cause,
);
debug!("suggest_missing_await: projection_type {:?}", normalized_ty);
let predicate =
ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
projection_ty,