diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-10-28 01:21:10 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-28 01:21:10 +0100 |
| commit | 86a4a381772a06ecf6c20384a1b32a49ea1574e0 (patch) | |
| tree | b465619b1417d3469f624b30ffcd7c6805a13859 /compiler | |
| parent | 346aeef496b5e6daaffb7f71b21d4cf003b44256 (diff) | |
| parent | 28f02fbf3e26738047135a577622a313a1c3bfb3 (diff) | |
| download | rust-86a4a381772a06ecf6c20384a1b32a49ea1574e0.tar.gz rust-86a4a381772a06ecf6c20384a1b32a49ea1574e0.zip | |
Rollup merge of #78297 - estebank:match-semicolon-2, r=oli-obk
Suggest calling await on method call and field access When encountering a failing method or field resolution on a `Future`, look at the `Output` and try the same operation on it. If successful, suggest calling `.await` on the `Future`. This had already been introduced in #72784, but at some point they stopped working. Built on top of #78214, only last commit is relevant. r? @oli-obk
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/expr.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/method/suggest.rs | 54 |
3 files changed, 41 insertions, 86 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index f7e4ace8fc5..1402f70c220 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1669,7 +1669,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.note_error_origin(diag, cause, exp_found); } - fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { + pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { if let ty::Opaque(def_id, substs) = ty.kind() { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); // Future::Output diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 5eba7be3b02..324aa1a66a6 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -42,7 +42,7 @@ use rustc_middle::ty::{AdtKind, Visibility}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::fmt::Display; @@ -1583,51 +1583,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, field_ident: Ident, base: &'tcx hir::Expr<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - def_id: DefId, + ty: Ty<'tcx>, ) { - let param_env = self.tcx().param_env(def_id); - 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 projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); - debug!("suggest_await_on_field_access: projection_ty={:?}", projection_ty); - - let cause = self.misc(expr.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, - param_env, - projection_ty, - cause, - 0, - &mut obligations, - ); - debug!( - "suggest_await_on_field_access: normalized_ty={:?}, ty_kind={:?}", - self.resolve_vars_if_possible(&normalized_ty), - normalized_ty.kind(), - ); - if let ty::Adt(def, _) = normalized_ty.kind() { - // no field access on enum type - if !def.is_enum() { - if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) - { - err.span_suggestion_verbose( - base.span.shrink_to_hi(), - "consider awaiting before field access", - ".await".to_string(), - Applicability::MaybeIncorrect, - ); - } + let output_ty = match self.infcx.get_impl_future_output_ty(ty) { + Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + _ => return, + }; + let mut add_label = true; + if let ty::Adt(def, _) = output_ty.kind() { + // no field access on enum type + if !def.is_enum() { + if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) { + add_label = false; + err.span_label( + field_ident.span, + "field not available in `impl Future`, but it is available in its `Output`", + ); + err.span_suggestion_verbose( + base.span.shrink_to_hi(), + "consider `await`ing on the `Future` and access the field of its `Output`", + ".await".to_string(), + Applicability::MaybeIncorrect, + ); } } } + if add_label { + err.span_label(field_ident.span, &format!("field not found in `{}`", ty)); + } } fn ban_nonexisting_field( @@ -1656,8 +1639,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); } - ty::Opaque(def_id, _) => { - self.suggest_await_on_field_access(&mut err, field, base, expr, def_id); + ty::Opaque(_, _) => { + self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs()); } _ => {} } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 6d2ffadc20c..46afe4892db 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -21,7 +21,6 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::Obligation; -use rustc_trait_selection::traits::SelectionContext; use std::cmp::Ordering; @@ -870,46 +869,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call: &hir::Expr<'_>, span: Span, ) { - if let ty::Opaque(def_id, _) = *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 projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); - 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 method_exists { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "consider awaiting before this method call", - "await.".to_string(), - Applicability::MaybeIncorrect, - ); - } - } + let output_ty = match self.infcx.get_impl_future_output_ty(ty) { + Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + _ => return, + }; + let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true); + debug!("suggest_await_before_method: is_method_exist={}", method_exists); + if method_exists { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider `await`ing on the `Future` and calling the method on its `Output`", + "await.".to_string(), + Applicability::MaybeIncorrect, + ); } } |
