mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
suggest await before method
This commit is contained in:
parent
1de0dd9531
commit
2271b081eb
@ -31,7 +31,6 @@ use rustc_infer::infer;
|
|||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
use rustc_middle::ty::TypeFoldable;
|
use rustc_middle::ty::TypeFoldable;
|
||||||
use rustc_middle::ty::{AdtKind, Visibility};
|
use rustc_middle::ty::{AdtKind, Visibility};
|
||||||
@ -1517,22 +1516,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
base: &'tcx hir::Expr<'tcx>,
|
base: &'tcx hir::Expr<'tcx>,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
substs: SubstsRef<'tcx>,
|
|
||||||
) {
|
) {
|
||||||
let param_env = self.tcx().param_env(def_id);
|
let param_env = self.tcx().param_env(def_id);
|
||||||
let future_trait = self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None);
|
let future_trait = self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None);
|
||||||
let future_trait_ref = ty::TraitRef { def_id: future_trait, substs };
|
|
||||||
// Future::Output
|
// Future::Output
|
||||||
let future_projection = ty::ProjectionTy::from_ref_and_name(
|
let item_def_id =
|
||||||
self.tcx,
|
self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id;
|
||||||
future_trait_ref,
|
|
||||||
Ident::with_dummy_span(sym::Output),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut projection_ty = None;
|
let mut projection_ty = None;
|
||||||
for (predicate, _) in self.tcx.predicates_of(def_id).predicates {
|
for (predicate, _) in self.tcx.predicates_of(def_id).predicates {
|
||||||
if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
|
if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
|
||||||
if future_projection.item_def_id == projection_predicate.projection_ty.item_def_id {
|
if item_def_id == projection_predicate.projection_ty.item_def_id {
|
||||||
projection_ty = Some(projection_predicate.projection_ty);
|
projection_ty = Some(projection_predicate.projection_ty);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1600,8 +1594,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty::Param(param_ty) => {
|
ty::Param(param_ty) => {
|
||||||
self.point_at_param_definition(&mut err, param_ty);
|
self.point_at_param_definition(&mut err, param_ty);
|
||||||
}
|
}
|
||||||
ty::Opaque(def_id, subts) => {
|
ty::Opaque(def_id, _) => {
|
||||||
self.suggest_await_on_field_access(&mut err, field, base, expr, def_id, subts);
|
self.suggest_await_on_field_access(&mut err, field, base, expr, def_id);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use rustc_span::symbol::{kw, sym, Ident};
|
|||||||
use rustc_span::{source_map, FileName, Span};
|
use rustc_span::{source_map, FileName, Span};
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::Obligation;
|
use rustc_trait_selection::traits::Obligation;
|
||||||
|
use rustc_trait_selection::traits::SelectionContext;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
@ -392,6 +393,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
actual.prefix_string(),
|
actual.prefix_string(),
|
||||||
ty_str,
|
ty_str,
|
||||||
);
|
);
|
||||||
|
if let Mode::MethodCall = mode {
|
||||||
|
if let SelfSource::MethodCall(call) = source {
|
||||||
|
self.suggest_await_before_method(
|
||||||
|
&mut err, item_name, actual, call, span,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(span) =
|
if let Some(span) =
|
||||||
tcx.sess.confused_type_with_std_module.borrow().get(&span)
|
tcx.sess.confused_type_with_std_module.borrow().get(&span)
|
||||||
{
|
{
|
||||||
@ -854,6 +862,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn suggest_await_before_method(
|
||||||
|
&self,
|
||||||
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
item_name: Ident,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
call: &hir::Expr<'_>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
if let ty::Opaque(def_id, _substs) = ty.kind {
|
||||||
|
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||||
|
// Future::Output
|
||||||
|
let item_def_id = self
|
||||||
|
.tcx
|
||||||
|
.associated_items(future_trait)
|
||||||
|
.in_definition_order()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.def_id;
|
||||||
|
|
||||||
|
let mut projection_ty = None;
|
||||||
|
for (predicate, _) in self.tcx.predicates_of(def_id).predicates {
|
||||||
|
if let ty::PredicateAtom::Projection(projection_predicate) =
|
||||||
|
predicate.skip_binders()
|
||||||
|
{
|
||||||
|
if item_def_id == projection_predicate.projection_ty.item_def_id {
|
||||||
|
projection_ty = Some(projection_predicate.projection_ty);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let cause = self.misc(span);
|
||||||
|
let mut selcx = SelectionContext::new(&self.infcx);
|
||||||
|
let mut obligations = vec![];
|
||||||
|
if let Some(projection_ty) = projection_ty {
|
||||||
|
let normalized_ty = rustc_trait_selection::traits::normalize_projection_type(
|
||||||
|
&mut selcx,
|
||||||
|
self.param_env,
|
||||||
|
projection_ty,
|
||||||
|
cause,
|
||||||
|
0,
|
||||||
|
&mut obligations,
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
"suggest_await_before_method: normalized_ty={:?}, ty_kind={:?}",
|
||||||
|
self.resolve_vars_if_possible(&normalized_ty),
|
||||||
|
normalized_ty.kind,
|
||||||
|
);
|
||||||
|
let method_exists = self.method_exists(item_name, normalized_ty, call.hir_id, true);
|
||||||
|
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
|
||||||
|
if let Ok(sp) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||||
|
if method_exists {
|
||||||
|
err.span_suggestion(
|
||||||
|
span,
|
||||||
|
"consider await before this method call",
|
||||||
|
format!("await.{}", sp),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn suggest_use_candidates(
|
fn suggest_use_candidates(
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
@ -12,6 +12,10 @@ struct Struct {
|
|||||||
a: i32
|
a: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Struct {
|
||||||
|
fn method(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
impl Future for Struct {
|
impl Future for Struct {
|
||||||
type Output = Struct;
|
type Output = Struct;
|
||||||
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { Poll::Pending }
|
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { Poll::Pending }
|
||||||
@ -55,6 +59,8 @@ async fn baz() -> Result<(), ()> {
|
|||||||
|
|
||||||
let _: i32 = struct_().a; //~ ERROR no field `a`
|
let _: i32 = struct_().a; //~ ERROR no field `a`
|
||||||
|
|
||||||
|
struct_().method(); //~ ERROR no method named
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
|
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
|
||||||
--> $DIR/issue-61076.rs:38:5
|
--> $DIR/issue-61076.rs:42:5
|
||||||
|
|
|
|
||||||
LL | foo()?;
|
LL | foo()?;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
@ -11,7 +11,7 @@ LL | foo()?;
|
|||||||
= note: required by `std::ops::Try::into_result`
|
= note: required by `std::ops::Try::into_result`
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
|
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
|
||||||
--> $DIR/issue-61076.rs:52:5
|
--> $DIR/issue-61076.rs:56:5
|
||||||
|
|
|
|
||||||
LL | t?;
|
LL | t?;
|
||||||
| ^^
|
| ^^
|
||||||
@ -23,7 +23,7 @@ LL | t?;
|
|||||||
= note: required by `std::ops::Try::into_result`
|
= note: required by `std::ops::Try::into_result`
|
||||||
|
|
||||||
error[E0609]: no field `0` on type `impl std::future::Future`
|
error[E0609]: no field `0` on type `impl std::future::Future`
|
||||||
--> $DIR/issue-61076.rs:54:26
|
--> $DIR/issue-61076.rs:58:26
|
||||||
|
|
|
|
||||||
LL | let _: i32 = tuple().0;
|
LL | let _: i32 = tuple().0;
|
||||||
| --------^
|
| --------^
|
||||||
@ -31,14 +31,23 @@ LL | let _: i32 = tuple().0;
|
|||||||
| help: consider await before field access: `tuple().await.0`
|
| help: consider await before field access: `tuple().await.0`
|
||||||
|
|
||||||
error[E0609]: no field `a` on type `impl std::future::Future`
|
error[E0609]: no field `a` on type `impl std::future::Future`
|
||||||
--> $DIR/issue-61076.rs:56:28
|
--> $DIR/issue-61076.rs:60:28
|
||||||
|
|
|
|
||||||
LL | let _: i32 = struct_().a;
|
LL | let _: i32 = struct_().a;
|
||||||
| ----------^
|
| ----------^
|
||||||
| |
|
| |
|
||||||
| help: consider await before field access: `struct_().await.a`
|
| help: consider await before field access: `struct_().await.a`
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error[E0599]: no method named `method` found for opaque type `impl std::future::Future` in the current scope
|
||||||
|
--> $DIR/issue-61076.rs:62:15
|
||||||
|
|
|
||||||
|
LL | struct_().method();
|
||||||
|
| ^^^^^^
|
||||||
|
| |
|
||||||
|
| method not found in `impl std::future::Future`
|
||||||
|
| help: consider await before this method call: `await.method`
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0609.
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0277, E0599, E0609.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
Loading…
Reference in New Issue
Block a user