diff options
| author | csmoe <csmoe@msn.com> | 2020-05-14 23:07:46 +0800 |
|---|---|---|
| committer | csmoe <csmoe@msn.com> | 2020-05-15 15:37:11 +0800 |
| commit | 10d7da4e0b07f469c9d2b8215b563528adfc7e99 (patch) | |
| tree | 26f82f9775f77d404e32f3741d86d4454beb80ea /src/librustc_trait_selection/traits | |
| parent | a1104b4dea0e0d3b35fa73c7f7c186f76b23db78 (diff) | |
| download | rust-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.rs | 37 | ||||
| -rw-r--r-- | src/librustc_trait_selection/traits/mod.rs | 42 |
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 }; } |
