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;
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
[] DropckOutlives(CanonicalTyGoal<'tcx>),
+ [] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
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;
--- /dev/null
+// 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
+ }
+}
use ty::{self, Ty};
pub mod dropck_outlives;
+pub mod evaluate_obligation;
pub mod normalize;
pub mod normalize_erasing_regions;
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;
/// 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
}
impl EvaluationResult {
- fn may_apply(self) -> bool {
+ pub fn may_apply(self) -> bool {
match self {
EvaluatedToOk |
EvaluatedToAmbig |
}
}
+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> {
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)
}
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.
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;
}
}
+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)
//! 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;
DUMMY_SP
}
}
+
+impl<'tcx> Key for CanonicalPredicateGoal<'tcx> {
+ fn map_crate(&self) -> CrateNum {
+ LOCAL_CRATE
+ }
+
+ fn default_span(&self, _tcx: TyCtxt) -> Span {
+ DUMMY_SP
+ }
+}
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,
DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions |
DepKind::DropckOutlives |
+ DepKind::EvaluateObligation |
DepKind::SubstituteNormalizeAndTestPredicates |
DepKind::InstanceDefSizeEstimate |
DepKind::ProgramClausesForEnv |
--- /dev/null
+// 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)
+ }
+ }
+ })
+}
extern crate syntax_pos;
mod dropck_outlives;
+mod evaluate_obligation;
mod normalize_projection_ty;
mod normalize_erasing_regions;
mod util;
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
};
}