1
Fork 0

Create a canonical trait query for evaluate_obligation

This commit is contained in:
Aravind Gollakota 2018-03-08 18:30:37 -06:00
parent 79f71f976a
commit 3ab3a9f509
11 changed files with 155 additions and 15 deletions

View file

@ -70,7 +70,8 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use syntax_pos::symbol::InternedString; 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::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
use ty::subst::Substs; use ty::subst::Substs;
@ -643,6 +644,7 @@ define_dep_nodes!( <'tcx>
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>), [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>), [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
[] DropckOutlives(CanonicalTyGoal<'tcx>), [] DropckOutlives(CanonicalTyGoal<'tcx>),
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },

View file

@ -41,7 +41,7 @@ pub use self::object_safety::ObjectSafetyViolation;
pub use self::object_safety::MethodViolationCode; pub use self::object_safety::MethodViolationCode;
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; 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::{OverlapError, specialization_graph, translate_substs};
pub use self::specialize::{SpecializesCache, find_associated_item}; pub use self::specialize::{SpecializesCache, find_associated_item};
pub use self::engine::TraitEngine; pub use self::engine::TraitEngine;

View file

@ -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
}
}

View file

@ -19,6 +19,7 @@ use infer::canonical::Canonical;
use ty::{self, Ty}; use ty::{self, Ty};
pub mod dropck_outlives; pub mod dropck_outlives;
pub mod evaluate_obligation;
pub mod normalize; pub mod normalize;
pub mod normalize_erasing_regions; pub mod normalize_erasing_regions;
@ -27,6 +28,9 @@ pub type CanonicalProjectionGoal<'tcx> =
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; 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)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct NoSolution; pub struct NoSolution;

View file

@ -319,7 +319,7 @@ enum BuiltinImplConditions<'tcx> {
/// all the "potential success" candidates can potentially succeed, /// all the "potential success" candidates can potentially succeed,
/// so they are no-ops when unioned with a definite error, and within /// 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. /// the categories it's easy to see that the unions are correct.
enum EvaluationResult { pub enum EvaluationResult {
/// Evaluation successful /// Evaluation successful
EvaluatedToOk, EvaluatedToOk,
/// Evaluation is known to be ambiguous - it *might* hold for some /// Evaluation is known to be ambiguous - it *might* hold for some
@ -385,7 +385,7 @@ enum EvaluationResult {
} }
impl EvaluationResult { impl EvaluationResult {
fn may_apply(self) -> bool { pub fn may_apply(self) -> bool {
match self { match self {
EvaluatedToOk | EvaluatedToOk |
EvaluatedToAmbig | EvaluatedToAmbig |
@ -408,10 +408,18 @@ impl EvaluationResult {
} }
} }
impl_stable_hash_for!(enum self::EvaluationResult {
EvaluatedToOk,
EvaluatedToAmbig,
EvaluatedToUnknown,
EvaluatedToRecur,
EvaluatedToErr
});
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
/// Indicates that trait evaluation caused overflow. Stores the obligation /// Indicates that trait evaluation caused overflow. Stores the obligation
/// that hit the recursion limit. /// 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> { impl<'tcx> From<OverflowError<'tcx>> for SelectionError<'tcx> {
fn from(OverflowError(o): OverflowError<'tcx>) -> SelectionError<'tcx> { fn from(OverflowError(o): OverflowError<'tcx>) -> SelectionError<'tcx> {
@ -574,9 +582,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("evaluate_obligation({:?})", debug!("evaluate_obligation({:?})",
obligation); obligation);
match self.probe(|this, _| { match self.evaluate_obligation_recursively(obligation) {
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
}) {
Ok(result) => result.may_apply(), Ok(result) => result.may_apply(),
Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true) Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
} }
@ -592,14 +598,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("evaluate_obligation_conservatively({:?})", debug!("evaluate_obligation_conservatively({:?})",
obligation); obligation);
match self.probe(|this, _| { match self.evaluate_obligation_recursively(obligation) {
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
}) {
Ok(result) => result == EvaluatedToOk, Ok(result) => result == EvaluatedToOk,
Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true) 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 /// Evaluates the predicates in `predicates` recursively. Note that
/// this applies projections in the predicates, and therefore /// this applies projections in the predicates, and therefore
/// is run within an inference probe. /// is run within an inference probe.

View file

@ -11,7 +11,7 @@
use dep_graph::SerializedDepNodeIndex; use dep_graph::SerializedDepNodeIndex;
use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::def_id::{CrateNum, DefId, DefIndex};
use mir::interpret::{GlobalId}; use mir::interpret::{GlobalId};
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal}; use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::Substs; use ty::subst::Substs;
use ty::maps::queries; use ty::maps::queries;
@ -73,6 +73,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_region
} }
} }
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> { impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
format!("computing whether `{}` is `Copy`", env.value) format!("computing whether `{}` is `Copy`", env.value)

View file

@ -11,7 +11,7 @@
//! Defines the set of legal keys that can be used in queries. //! Defines the set of legal keys that can be used in queries.
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; 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::{self, Ty, TyCtxt};
use ty::subst::Substs; use ty::subst::Substs;
use ty::fast_reject::SimplifiedType; use ty::fast_reject::SimplifiedType;
@ -200,3 +200,13 @@ impl<'tcx> Key for CanonicalTyGoal<'tcx> {
DUMMY_SP DUMMY_SP
} }
} }
impl<'tcx> Key for CanonicalPredicateGoal<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _tcx: TyCtxt) -> Span {
DUMMY_SP
}
}

View file

@ -32,8 +32,9 @@ use mir;
use mir::interpret::{GlobalId}; use mir::interpret::{GlobalId};
use session::{CompileResult, CrateDisambiguator}; use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames; use session::config::OutputFilenames;
use traits::Vtable; use traits::{self, Vtable};
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution}; use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal,
CanonicalTyGoal, NoSolution};
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
use traits::query::normalize::NormalizationResult; use traits::query::normalize::NormalizationResult;
use traits::specialization_graph; use traits::specialization_graph;
@ -433,6 +434,11 @@ define_maps! { <'tcx>
NoSolution, 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: [] fn substitute_normalize_and_test_predicates:
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,

View file

@ -977,6 +977,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::NormalizeProjectionTy | DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions | DepKind::NormalizeTyAfterErasingRegions |
DepKind::DropckOutlives | DepKind::DropckOutlives |
DepKind::EvaluateObligation |
DepKind::SubstituteNormalizeAndTestPredicates | DepKind::SubstituteNormalizeAndTestPredicates |
DepKind::InstanceDefSizeEstimate | DepKind::InstanceDefSizeEstimate |
DepKind::ProgramClausesForEnv | DepKind::ProgramClausesForEnv |

View file

@ -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)
}
}
})
}

View file

@ -22,6 +22,7 @@ extern crate syntax;
extern crate syntax_pos; extern crate syntax_pos;
mod dropck_outlives; mod dropck_outlives;
mod evaluate_obligation;
mod normalize_projection_ty; mod normalize_projection_ty;
mod normalize_erasing_regions; mod normalize_erasing_regions;
mod util; mod util;
@ -38,6 +39,7 @@ pub fn provide(p: &mut Providers) {
normalize_erasing_regions::normalize_ty_after_erasing_regions, normalize_erasing_regions::normalize_ty_after_erasing_regions,
program_clauses_for: lowering::program_clauses_for, program_clauses_for: lowering::program_clauses_for,
program_clauses_for_env: lowering::program_clauses_for_env, program_clauses_for_env: lowering::program_clauses_for_env,
evaluate_obligation: evaluate_obligation::evaluate_obligation,
..*p ..*p
}; };
} }