about summary refs log tree commit diff
path: root/src/librustc_trait_selection/traits
diff options
context:
space:
mode:
authorcsmoe <csmoe@msn.com>2020-05-14 23:07:46 +0800
committercsmoe <csmoe@msn.com>2020-05-15 15:37:11 +0800
commit10d7da4e0b07f469c9d2b8215b563528adfc7e99 (patch)
tree26f82f9775f77d404e32f3741d86d4454beb80ea /src/librustc_trait_selection/traits
parenta1104b4dea0e0d3b35fa73c7f7c186f76b23db78 (diff)
downloadrust-10d7da4e0b07f469c9d2b8215b563528adfc7e99.tar.gz
rust-10d7da4e0b07f469c9d2b8215b563528adfc7e99.zip
implement type_implments_trait query
Diffstat (limited to 'src/librustc_trait_selection/traits')
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs37
-rw-r--r--src/librustc_trait_selection/traits/mod.rs42
2 files changed, 60 insertions, 19 deletions
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 5e3b383ff25..d5b2b765e93 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -11,6 +11,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::TypeckTables;
 use rustc_middle::ty::{
@@ -1785,29 +1786,30 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         span: Span,
     ) {
         debug!(
-            "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}",
-            obligation, span, trait_ref
+            "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}",
+            obligation,
+            span,
+            trait_ref,
+            trait_ref.self_ty()
         );
         let body_hir_id = obligation.cause.body_id;
         let item_id = self.tcx.hir().get_parent_node(body_hir_id);
 
-        let mut is_future = false;
-        if let ty::Opaque(def_id, substs) = trait_ref.self_ty().kind {
-            let preds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
-            for p in preds.predicates {
-                if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
-                    if Some(trait_ref.def_id()) == self.tcx.lang_items().future_trait() {
-                        is_future = true;
-                        break;
-                    }
-                }
-            }
-        }
-
         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 {
-                let future_trait = self.tcx.lang_items().future_trait().unwrap();
+                let future_trait =
+                    self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None);
+
+                let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty());
+
+                let impls_future = self.tcx.type_implements_trait((
+                    future_trait,
+                    self_ty,
+                    ty::List::empty(),
+                    obligation.param_env,
+                ));
+
                 let item_def_id = self
                     .tcx
                     .associated_items(future_trait)
@@ -1815,7 +1817,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     .next()
                     .unwrap()
                     .def_id;
-                debug!("trait_ref_self_ty: {:?}", trait_ref.self_ty());
                 // `<T as Future>::Output`
                 let projection_ty = ty::ProjectionTy {
                     // `T`
@@ -1850,7 +1851,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     obligation.param_env,
                 );
                 debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation);
-                if self.predicate_may_hold(&try_obligation) && is_future {
+                if self.predicate_may_hold(&try_obligation) && impls_future {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                         if snippet.ends_with('?') {
                             err.span_suggestion(
diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs
index 778430fc2ca..9592f93ce2e 100644
--- a/src/librustc_trait_selection/traits/mod.rs
+++ b/src/librustc_trait_selection/traits/mod.rs
@@ -31,7 +31,9 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::middle::region;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{
+    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness,
+};
 use rustc_span::Span;
 
 use std::fmt::Debug;
@@ -523,6 +525,43 @@ fn vtable_methods<'tcx>(
     }))
 }
 
+/// Check whether a `ty` implements given trait(trait_def_id).
+///
+/// NOTE: Always return `false` for a type which needs inference.
+fn type_implements_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (
+        DefId,    // trait_def_id,
+        Ty<'tcx>, // type
+        SubstsRef<'tcx>,
+        ParamEnv<'tcx>,
+    ),
+) -> bool {
+    let (trait_def_id, ty, params, param_env) = key;
+
+    debug!(
+        "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
+        trait_def_id, ty, params, param_env
+    );
+
+    // Do not check on infer_types to avoid panic in evaluate_obligation.
+    if ty.has_infer_types() {
+        return false;
+    }
+
+    let ty = tcx.erase_regions(&ty);
+
+    let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
+
+    let obligation = Obligation {
+        cause: ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: trait_ref.without_const().to_predicate(),
+    };
+    tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+}
+
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     object_safety::provide(providers);
     *providers = ty::query::Providers {
@@ -531,6 +570,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
         vtable_methods,
         substitute_normalize_and_test_predicates,
+        type_implements_trait,
         ..*providers
     };
 }