Skip to content

Commit 627f473

Browse files
committed
suggest await before try when performing trait selection
1 parent 114cd00 commit 627f473

File tree

4 files changed

+92
-10
lines changed

4 files changed

+92
-10
lines changed

src/libcore/ops/try.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
)
2626
)]
2727
#[doc(alias = "?")]
28-
#[cfg_attr(not(bootstrap), lang = "try_trait")]
28+
#[cfg_attr(not(bootstrap), lang = "try_trait")]
2929
pub trait Try {
3030
/// The type of this value when viewed as successful.
3131
#[unstable(feature = "try_trait", issue = "42327")]

src/librustc_trait_selection/traits/error_reporting/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
400400
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
401401
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
402402
self.note_version_mismatch(&mut err, &trait_ref);
403+
//self.sugggest_await_before_try(&mut err, &obligation, &trait_ref);
404+
debug!(
405+
"suggest_await_befor_try: trait_predicate={:?} obligation={:?}, trait_ref={:?}",
406+
trait_predicate, obligation, trait_ref
407+
);
408+
self.suggest_await_befor_try(
409+
&mut err,
410+
&obligation,
411+
trait_ref.self_ty(),
412+
span,
413+
);
403414
if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
404415
err.emit();
405416
return;

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use super::{
22
EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
3+
SelectionContext,
34
};
45

56
use crate::infer::InferCtxt;
7+
use crate::traits::normalize_projection_type;
68

79
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
810
use rustc_hir as hir;
@@ -150,6 +152,15 @@ pub trait InferCtxtExt<'tcx> {
150152
T: fmt::Display;
151153

152154
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
155+
156+
/// Suggest to await before try: future? => future.await?
157+
fn suggest_await_befor_try(
158+
&self,
159+
err: &mut DiagnosticBuilder<'_>,
160+
obligation: &PredicateObligation<'tcx>,
161+
ty: Ty<'tcx>,
162+
span: Span,
163+
);
153164
}
154165

155166
fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
@@ -1765,6 +1776,75 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
17651776
suggested_limit, self.tcx.crate_name,
17661777
));
17671778
}
1779+
1780+
fn suggest_await_befor_try(
1781+
&self,
1782+
err: &mut DiagnosticBuilder<'_>,
1783+
obligation: &PredicateObligation<'tcx>,
1784+
ty: Ty<'tcx>,
1785+
span: Span,
1786+
) {
1787+
debug!("suggest_await_befor_try: obligation={:?}, span={:?}", obligation, span);
1788+
let body_hir_id = obligation.cause.body_id;
1789+
let item_id = self.tcx.hir().get_parent_node(body_hir_id);
1790+
if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) {
1791+
let body = self.tcx.hir().body(body_id);
1792+
if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
1793+
// Check for `Future` implementations by constructing a predicate to
1794+
// prove: `<T as Future>::Output == U`
1795+
let future_trait = self.tcx.lang_items().future_trait().unwrap();
1796+
let item_def_id = self
1797+
.tcx
1798+
.associated_items(future_trait)
1799+
.in_definition_order()
1800+
.next()
1801+
.unwrap()
1802+
.def_id;
1803+
// `<T as Future>::Output`
1804+
let projection_ty = ty::ProjectionTy {
1805+
// `T`
1806+
substs: self
1807+
.tcx
1808+
.mk_substs_trait(ty, self.fresh_substs_for_item(span, item_def_id)),
1809+
// `Future::Output`
1810+
item_def_id,
1811+
};
1812+
1813+
let cause = ObligationCause::misc(span, body_hir_id);
1814+
let mut selcx = SelectionContext::new(self);
1815+
1816+
let mut obligations = vec![];
1817+
let normalized_ty = normalize_projection_type(
1818+
&mut selcx,
1819+
obligation.param_env,
1820+
projection_ty,
1821+
obligation.cause.clone(),
1822+
0,
1823+
&mut obligations,
1824+
);
1825+
1826+
debug!("suggest_await_befor_try: normalized_projection_type {:?}", normalized_ty);
1827+
let try_trait_ref_id = self.tcx.lang_items().try_trait().unwrap();
1828+
if let Some(try_trait_ref) = self.tcx.impl_trait_ref(try_trait_ref_id) {
1829+
let try_predicate = try_trait_ref.without_const().to_predicate();
1830+
let try_obligation =
1831+
Obligation::new(cause, obligation.param_env, try_predicate);
1832+
debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation);
1833+
if self.predicate_may_hold(&try_obligation) {
1834+
debug!("try_obligation holds");
1835+
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
1836+
err.span_suggestion(
1837+
span,
1838+
"consider using `.await` here",
1839+
format!("{}.await", snippet),
1840+
Applicability::MaybeIncorrect,
1841+
);
1842+
}
1843+
}
1844+
}
1845+
}
1846+
}
1847+
}
17681848
}
17691849

17701850
/// Collect all the returned expressions within the input expression.

src/librustc_typeck/check/mod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5317,15 +5317,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
53175317
item_def_id,
53185318
};
53195319

5320-
let cause = traits::ObligationCause::misc(sp, self.body_id);
5321-
let normalized_ty = self.fulfillment_cx.borrow_mut().normalize_projection_type(
5322-
&self.infcx,
5323-
self.param_env,
5324-
projection_ty,
5325-
cause,
5326-
);
5327-
debug!("suggest_missing_await: projection_type {:?}", normalized_ty);
5328-
53295320
let predicate =
53305321
ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
53315322
projection_ty,

0 commit comments

Comments
 (0)