]> git.lizzy.rs Git - rust.git/commitdiff
Create a canonical trait query for `evaluate_obligation`
authorAravind Gollakota <aravindprasant@gmail.com>
Fri, 9 Mar 2018 00:30:37 +0000 (18:30 -0600)
committerAravind Gollakota <aravindprasant@gmail.com>
Fri, 27 Apr 2018 01:28:29 +0000 (20:28 -0500)
src/librustc/dep_graph/dep_node.rs
src/librustc/traits/mod.rs
src/librustc/traits/query/evaluate_obligation.rs [new file with mode: 0644]
src/librustc/traits/query/mod.rs
src/librustc/traits/select.rs
src/librustc/ty/maps/config.rs
src/librustc/ty/maps/keys.rs
src/librustc/ty/maps/mod.rs
src/librustc/ty/maps/plumbing.rs
src/librustc_traits/evaluate_obligation.rs [new file with mode: 0644]
src/librustc_traits/lib.rs

index 18bf54297afc6b3d100e6835c5baf647a0aa0819..e4f432e7caf494d789bd520299e6774db9cb22bd 100644 (file)
@@ -70,7 +70,8 @@
 use std::fmt;
 use std::hash::Hash;
 use syntax_pos::symbol::InternedString;
-use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
+use traits::query::{CanonicalProjectionGoal,
+                    CanonicalTyGoal, CanonicalPredicateGoal};
 use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
 use ty::subst::Substs;
 
@@ -643,6 +644,7 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
     [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
     [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
     [] DropckOutlives(CanonicalTyGoal<'tcx>),
+    [] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
 
     [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
 
index 6101d37956afd3716f95cb17b2e035381ff281db..031a3677aa330c54d5976ee59fd3ff27cc62af04 100644 (file)
@@ -41,7 +41,7 @@
 pub use self::object_safety::MethodViolationCode;
 pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
 pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
-pub use self::select::IntercrateAmbiguityCause;
+pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
 pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
 pub use self::specialize::{SpecializesCache, find_associated_item};
 pub use self::engine::TraitEngine;
diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs
new file mode 100644 (file)
index 0000000..88c51d0
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use infer::InferCtxt;
+use infer::canonical::{Canonical, Canonicalize};
+use traits::{EvaluationResult, PredicateObligation};
+use traits::query::CanonicalPredicateGoal;
+use ty::{ParamEnvAnd, Predicate, TyCtxt};
+
+impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
+    /// Evaluates whether the predicate can be satisfied (by any means)
+    /// in the given `ParamEnv`.
+    pub fn predicate_may_hold(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> bool {
+        let (c_pred, _) =
+            self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
+
+        self.tcx.global_tcx().evaluate_obligation(c_pred).may_apply()
+    }
+
+    /// Evaluates whether the predicate can be satisfied in the given
+    /// `ParamEnv`, and returns `false` if not certain. However, this is
+    /// not entirely accurate if inference variables are involved.
+    pub fn predicate_must_hold(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> bool {
+        let (c_pred, _) =
+            self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
+
+        self.tcx.global_tcx().evaluate_obligation(c_pred) ==
+            EvaluationResult::EvaluatedToOk
+    }
+}
+
+impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> {
+    type Canonicalized = CanonicalPredicateGoal<'gcx>;
+
+    fn intern(
+        _gcx: TyCtxt<'_, 'gcx, 'gcx>,
+        value: Canonical<'gcx, Self::Lifted>,
+    ) -> Self::Canonicalized {
+        value
+    }
+}
index f1f9256f825373bca5101446e98f9ca7318292aa..096633ddab2f7893cb6961a27b4e357c0ae7bad3 100644 (file)
@@ -19,6 +19,7 @@
 use ty::{self, Ty};
 
 pub mod dropck_outlives;
+pub mod evaluate_obligation;
 pub mod normalize;
 pub mod normalize_erasing_regions;
 
@@ -27,6 +28,9 @@
 
 pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
 
+pub type CanonicalPredicateGoal<'tcx> =
+    Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct NoSolution;
 
index e65bfa7a72ecdd7128db9817e7d872ce540c52b7..3dedfcd357eb6b6f9466873cb5971b2fc6f824db 100644 (file)
@@ -319,7 +319,7 @@ enum BuiltinImplConditions<'tcx> {
 ///     all the "potential success" candidates can potentially succeed,
 ///     so they are no-ops when unioned with a definite error, and within
 ///     the categories it's easy to see that the unions are correct.
-enum EvaluationResult {
+pub enum EvaluationResult {
     /// Evaluation successful
     EvaluatedToOk,
     /// Evaluation is known to be ambiguous - it *might* hold for some
@@ -385,7 +385,7 @@ enum EvaluationResult {
 }
 
 impl EvaluationResult {
-    fn may_apply(self) -> bool {
+    pub fn may_apply(self) -> bool {
         match self {
             EvaluatedToOk |
             EvaluatedToAmbig |
@@ -408,10 +408,18 @@ fn is_stack_dependent(self) -> bool {
     }
 }
 
+impl_stable_hash_for!(enum self::EvaluationResult {
+    EvaluatedToOk,
+    EvaluatedToAmbig,
+    EvaluatedToUnknown,
+    EvaluatedToRecur,
+    EvaluatedToErr
+});
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 /// Indicates that trait evaluation caused overflow. Stores the obligation
 /// that hit the recursion limit.
-pub struct OverflowError<'tcx>(TraitObligation<'tcx>);
+pub struct OverflowError<'tcx>(pub TraitObligation<'tcx>);
 
 impl<'tcx> From<OverflowError<'tcx>> for SelectionError<'tcx> {
     fn from(OverflowError(o): OverflowError<'tcx>) -> SelectionError<'tcx> {
@@ -574,9 +582,7 @@ pub fn evaluate_obligation(&mut self,
         debug!("evaluate_obligation({:?})",
                obligation);
 
-        match self.probe(|this, _| {
-            this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
-        }) {
+        match self.evaluate_obligation_recursively(obligation) {
             Ok(result) => result.may_apply(),
             Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
         }
@@ -592,14 +598,23 @@ pub fn evaluate_obligation_conservatively(&mut self,
         debug!("evaluate_obligation_conservatively({:?})",
                obligation);
 
-        match self.probe(|this, _| {
-            this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
-        }) {
+        match self.evaluate_obligation_recursively(obligation) {
             Ok(result) => result == EvaluatedToOk,
             Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
         }
     }
 
+    /// Evaluates whether the obligation `obligation` can be satisfied and returns
+    /// an `EvaluationResult`.
+    pub fn evaluate_obligation_recursively(&mut self,
+                                           obligation: &PredicateObligation<'tcx>)
+                                           -> Result<EvaluationResult, OverflowError<'tcx>>
+    {
+        self.probe(|this, _| {
+            this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
+        })
+    }
+
     /// Evaluates the predicates in `predicates` recursively. Note that
     /// this applies projections in the predicates, and therefore
     /// is run within an inference probe.
index 735fe06560f5f3a765fbc561bc7085c0859a489f..1fd0632580cfc018ff96ac478533a84ec6ba9f42 100644 (file)
@@ -11,7 +11,7 @@
 use dep_graph::SerializedDepNodeIndex;
 use hir::def_id::{CrateNum, DefId, DefIndex};
 use mir::interpret::{GlobalId};
-use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
+use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
 use ty::{self, ParamEnvAnd, Ty, TyCtxt};
 use ty::subst::Substs;
 use ty::maps::queries;
@@ -73,6 +73,12 @@ fn describe(_tcx: TyCtxt, goal: ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> {
+    fn describe(_tcx: TyCtxt, goal: CanonicalPredicateGoal<'tcx>) -> String {
+        format!("evaluating trait selection obligation `{}`", goal.value.value)
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
     fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
         format!("computing whether `{}` is `Copy`", env.value)
index 72f2cb49abc0e73f837476907d7331f1a55ba656..da29f23589e85e7a5f464cc5d325d1fbc8b49787 100644 (file)
@@ -11,7 +11,7 @@
 //! Defines the set of legal keys that can be used in queries.
 
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
-use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
+use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
 use ty::{self, Ty, TyCtxt};
 use ty::subst::Substs;
 use ty::fast_reject::SimplifiedType;
@@ -200,3 +200,13 @@ fn default_span(&self, _tcx: TyCtxt) -> Span {
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for CanonicalPredicateGoal<'tcx> {
+    fn map_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+
+    fn default_span(&self, _tcx: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
index f5cb3643de8323a801a4b688f96beea75d532dc5..9343eccd38e9f059887df1903dd8d8ce61105516 100644 (file)
@@ -32,8 +32,9 @@
 use mir::interpret::{GlobalId};
 use session::{CompileResult, CrateDisambiguator};
 use session::config::OutputFilenames;
-use traits::Vtable;
-use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
+use traits::{self, Vtable};
+use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal,
+                    CanonicalTyGoal, NoSolution};
 use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use traits::query::normalize::NormalizationResult;
 use traits::specialization_graph;
         NoSolution,
     >,
 
+    /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
+    /// `infcx.predicate_must_hold()` instead.
+    [] fn evaluate_obligation:
+        EvaluateObligation(CanonicalPredicateGoal<'tcx>) -> traits::EvaluationResult,
+
     [] fn substitute_normalize_and_test_predicates:
         substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
 
index 61a4eb58531027d8435703525c5a94ae0967d2fe..1cde745d4d87f4d19851a1a49270de7dca087ad8 100644 (file)
@@ -977,6 +977,7 @@ macro_rules! force {
         DepKind::NormalizeProjectionTy |
         DepKind::NormalizeTyAfterErasingRegions |
         DepKind::DropckOutlives |
+        DepKind::EvaluateObligation |
         DepKind::SubstituteNormalizeAndTestPredicates |
         DepKind::InstanceDefSizeEstimate |
         DepKind::ProgramClausesForEnv |
diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs
new file mode 100644 (file)
index 0000000..f43733f
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::traits::{EvaluationResult, Obligation, ObligationCause,
+                    OverflowError, SelectionContext};
+use rustc::traits::query::CanonicalPredicateGoal;
+use rustc::ty::{ParamEnvAnd, TyCtxt};
+use syntax::codemap::DUMMY_SP;
+
+crate fn evaluate_obligation<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    goal: CanonicalPredicateGoal<'tcx>,
+) -> EvaluationResult {
+    tcx.infer_ctxt().enter(|ref infcx| {
+        let (
+            ParamEnvAnd {
+                param_env,
+                value: predicate,
+            },
+            _canonical_inference_vars,
+        ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
+
+        let mut selcx = SelectionContext::new(&infcx);
+        let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+
+        match selcx.evaluate_obligation_recursively(&obligation) {
+            Ok(result) => result,
+            Err(OverflowError(o)) => {
+                infcx.report_overflow_error(&o, true)
+            }
+        }
+    })
+}
index 90c870096e179f711af17cac046249fbc2a7d2e5..7f18fac2db5a3a5b8996c722c6959492ac4302c1 100644 (file)
@@ -22,6 +22,7 @@
 extern crate syntax_pos;
 
 mod dropck_outlives;
+mod evaluate_obligation;
 mod normalize_projection_ty;
 mod normalize_erasing_regions;
 mod util;
@@ -38,6 +39,7 @@ pub fn provide(p: &mut Providers) {
             normalize_erasing_regions::normalize_ty_after_erasing_regions,
         program_clauses_for: lowering::program_clauses_for,
         program_clauses_for_env: lowering::program_clauses_for_env,
+        evaluate_obligation: evaluate_obligation::evaluate_obligation,
         ..*p
     };
 }