Skip to content

Commit 2271b08

Browse files
committed
suggest await before method
1 parent 1de0dd9 commit 2271b08

File tree

4 files changed

+97
-17
lines changed

4 files changed

+97
-17
lines changed

src/librustc_typeck/check/expr.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ use rustc_infer::infer;
3131
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
3232
use rustc_middle::ty;
3333
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
34-
use rustc_middle::ty::subst::SubstsRef;
3534
use rustc_middle::ty::Ty;
3635
use rustc_middle::ty::TypeFoldable;
3736
use rustc_middle::ty::{AdtKind, Visibility};
@@ -1517,22 +1516,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15171516
base: &'tcx hir::Expr<'tcx>,
15181517
expr: &'tcx hir::Expr<'tcx>,
15191518
def_id: DefId,
1520-
substs: SubstsRef<'tcx>,
15211519
) {
15221520
let param_env = self.tcx().param_env(def_id);
15231521
let future_trait = self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None);
1524-
let future_trait_ref = ty::TraitRef { def_id: future_trait, substs };
15251522
// Future::Output
1526-
let future_projection = ty::ProjectionTy::from_ref_and_name(
1527-
self.tcx,
1528-
future_trait_ref,
1529-
Ident::with_dummy_span(sym::Output),
1530-
);
1523+
let item_def_id =
1524+
self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id;
15311525

15321526
let mut projection_ty = None;
15331527
for (predicate, _) in self.tcx.predicates_of(def_id).predicates {
15341528
if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
1535-
if future_projection.item_def_id == projection_predicate.projection_ty.item_def_id {
1529+
if item_def_id == projection_predicate.projection_ty.item_def_id {
15361530
projection_ty = Some(projection_predicate.projection_ty);
15371531
break;
15381532
}
@@ -1600,8 +1594,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16001594
ty::Param(param_ty) => {
16011595
self.point_at_param_definition(&mut err, param_ty);
16021596
}
1603-
ty::Opaque(def_id, subts) => {
1604-
self.suggest_await_on_field_access(&mut err, field, base, expr, def_id, subts);
1597+
ty::Opaque(def_id, _) => {
1598+
self.suggest_await_on_field_access(&mut err, field, base, expr, def_id);
16051599
}
16061600
_ => {}
16071601
}

src/librustc_typeck/check/method/suggest.rs

+71
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_span::symbol::{kw, sym, Ident};
2121
use rustc_span::{source_map, FileName, Span};
2222
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
2323
use rustc_trait_selection::traits::Obligation;
24+
use rustc_trait_selection::traits::SelectionContext;
2425

2526
use std::cmp::Ordering;
2627

@@ -392,6 +393,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
392393
actual.prefix_string(),
393394
ty_str,
394395
);
396+
if let Mode::MethodCall = mode {
397+
if let SelfSource::MethodCall(call) = source {
398+
self.suggest_await_before_method(
399+
&mut err, item_name, actual, call, span,
400+
);
401+
}
402+
}
395403
if let Some(span) =
396404
tcx.sess.confused_type_with_std_module.borrow().get(&span)
397405
{
@@ -854,6 +862,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
854862
}
855863
}
856864

865+
fn suggest_await_before_method(
866+
&self,
867+
err: &mut DiagnosticBuilder<'_>,
868+
item_name: Ident,
869+
ty: Ty<'tcx>,
870+
call: &hir::Expr<'_>,
871+
span: Span,
872+
) {
873+
if let ty::Opaque(def_id, _substs) = ty.kind {
874+
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
875+
// Future::Output
876+
let item_def_id = self
877+
.tcx
878+
.associated_items(future_trait)
879+
.in_definition_order()
880+
.next()
881+
.unwrap()
882+
.def_id;
883+
884+
let mut projection_ty = None;
885+
for (predicate, _) in self.tcx.predicates_of(def_id).predicates {
886+
if let ty::PredicateAtom::Projection(projection_predicate) =
887+
predicate.skip_binders()
888+
{
889+
if item_def_id == projection_predicate.projection_ty.item_def_id {
890+
projection_ty = Some(projection_predicate.projection_ty);
891+
break;
892+
}
893+
}
894+
}
895+
let cause = self.misc(span);
896+
let mut selcx = SelectionContext::new(&self.infcx);
897+
let mut obligations = vec![];
898+
if let Some(projection_ty) = projection_ty {
899+
let normalized_ty = rustc_trait_selection::traits::normalize_projection_type(
900+
&mut selcx,
901+
self.param_env,
902+
projection_ty,
903+
cause,
904+
0,
905+
&mut obligations,
906+
);
907+
debug!(
908+
"suggest_await_before_method: normalized_ty={:?}, ty_kind={:?}",
909+
self.resolve_vars_if_possible(&normalized_ty),
910+
normalized_ty.kind,
911+
);
912+
let method_exists = self.method_exists(item_name, normalized_ty, call.hir_id, true);
913+
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
914+
if let Ok(sp) = self.tcx.sess.source_map().span_to_snippet(span) {
915+
if method_exists {
916+
err.span_suggestion(
917+
span,
918+
"consider await before this method call",
919+
format!("await.{}", sp),
920+
Applicability::MaybeIncorrect,
921+
);
922+
}
923+
}
924+
}
925+
}
926+
}
927+
857928
fn suggest_use_candidates(
858929
&self,
859930
err: &mut DiagnosticBuilder<'_>,

src/test/ui/async-await/issue-61076.rs

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ struct Struct {
1212
a: i32
1313
}
1414

15+
impl Struct {
16+
fn method(&self) {}
17+
}
18+
1519
impl Future for Struct {
1620
type Output = Struct;
1721
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { Poll::Pending }
@@ -55,6 +59,8 @@ async fn baz() -> Result<(), ()> {
5559

5660
let _: i32 = struct_().a; //~ ERROR no field `a`
5761

62+
struct_().method(); //~ ERROR no method named
63+
5864
Ok(())
5965
}
6066

src/test/ui/async-await/issue-61076.stderr

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
2-
--> $DIR/issue-61076.rs:38:5
2+
--> $DIR/issue-61076.rs:42:5
33
|
44
LL | foo()?;
55
| ^^^^^^
@@ -11,7 +11,7 @@ LL | foo()?;
1111
= note: required by `std::ops::Try::into_result`
1212

1313
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
14-
--> $DIR/issue-61076.rs:52:5
14+
--> $DIR/issue-61076.rs:56:5
1515
|
1616
LL | t?;
1717
| ^^
@@ -23,22 +23,31 @@ LL | t?;
2323
= note: required by `std::ops::Try::into_result`
2424

2525
error[E0609]: no field `0` on type `impl std::future::Future`
26-
--> $DIR/issue-61076.rs:54:26
26+
--> $DIR/issue-61076.rs:58:26
2727
|
2828
LL | let _: i32 = tuple().0;
2929
| --------^
3030
| |
3131
| help: consider await before field access: `tuple().await.0`
3232

3333
error[E0609]: no field `a` on type `impl std::future::Future`
34-
--> $DIR/issue-61076.rs:56:28
34+
--> $DIR/issue-61076.rs:60:28
3535
|
3636
LL | let _: i32 = struct_().a;
3737
| ----------^
3838
| |
3939
| help: consider await before field access: `struct_().await.a`
4040

41-
error: aborting due to 4 previous errors
41+
error[E0599]: no method named `method` found for opaque type `impl std::future::Future` in the current scope
42+
--> $DIR/issue-61076.rs:62:15
43+
|
44+
LL | struct_().method();
45+
| ^^^^^^
46+
| |
47+
| method not found in `impl std::future::Future`
48+
| help: consider await before this method call: `await.method`
49+
50+
error: aborting due to 5 previous errors
4251

43-
Some errors have detailed explanations: E0277, E0609.
52+
Some errors have detailed explanations: E0277, E0599, E0609.
4453
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)