Skip to content

Commit 2d0113f

Browse files
aravind-pgnikomatsakis
authored andcommitted
Create a canonical trait query for evaluate_obligation
1 parent aafe7d8 commit 2d0113f

File tree

11 files changed

+151
-8
lines changed

11 files changed

+151
-8
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
7070
use std::fmt;
7171
use std::hash::Hash;
7272
use syntax_pos::symbol::InternedString;
73-
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
73+
use traits::query::{CanonicalProjectionGoal,
74+
CanonicalTyGoal, CanonicalPredicateGoal};
7475
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
7576
use ty::subst::Substs;
7677

@@ -638,6 +639,7 @@ define_dep_nodes!( <'tcx>
638639
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
639640
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
640641
[] DropckOutlives(CanonicalTyGoal<'tcx>),
642+
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
641643

642644
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
643645

src/librustc/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub use self::object_safety::ObjectSafetyViolation;
4242
pub use self::object_safety::MethodViolationCode;
4343
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
4444
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
45-
pub use self::select::IntercrateAmbiguityCause;
45+
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause};
4646
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
4747
pub use self::specialize::{SpecializesCache, find_associated_item};
4848
pub use self::util::elaborate_predicates;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use infer::InferCtxt;
12+
use infer::canonical::{Canonical, Canonicalize};
13+
use traits::EvaluationResult;
14+
use traits::query::CanonicalPredicateGoal;
15+
use ty::{ParamEnv, ParamEnvAnd, Predicate, TyCtxt};
16+
17+
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
18+
/// Evaluates whether the predicate can be satisfied (by any means)
19+
/// in the given `ParamEnv`.
20+
pub fn predicate_may_hold(
21+
&self,
22+
param_env: ParamEnv<'tcx>,
23+
predicate: Predicate<'tcx>,
24+
) -> bool {
25+
self.evaluate_obligation(param_env, predicate).may_apply()
26+
}
27+
28+
/// Evaluates whether the predicate can be satisfied in the given
29+
/// `ParamEnv`, and returns `false` if not certain. However, this is
30+
/// not entirely accurate if inference variables are involved.
31+
pub fn predicate_must_hold(
32+
&self,
33+
param_env: ParamEnv<'tcx>,
34+
predicate: Predicate<'tcx>,
35+
) -> bool {
36+
self.evaluate_obligation(param_env, predicate) == EvaluationResult::EvaluatedToOk
37+
}
38+
39+
fn evaluate_obligation(
40+
&self,
41+
param_env: ParamEnv<'tcx>,
42+
predicate: Predicate<'tcx>,
43+
) -> EvaluationResult {
44+
let (c_pred, _) = self.canonicalize_query(&param_env.and(predicate));
45+
46+
self.tcx.global_tcx().evaluate_obligation(c_pred)
47+
}
48+
}
49+
50+
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> {
51+
type Canonicalized = CanonicalPredicateGoal<'gcx>;
52+
53+
fn intern(
54+
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
55+
value: Canonical<'gcx, Self::Lifted>,
56+
) -> Self::Canonicalized {
57+
value
58+
}
59+
}

src/librustc/traits/query/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use infer::canonical::Canonical;
1919
use ty::{self, Ty};
2020

2121
pub mod dropck_outlives;
22+
pub mod evaluate_obligation;
2223
pub mod normalize;
2324
pub mod normalize_erasing_regions;
2425

@@ -27,6 +28,9 @@ pub type CanonicalProjectionGoal<'tcx> =
2728

2829
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
2930

31+
pub type CanonicalPredicateGoal<'tcx> =
32+
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
33+
3034
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
3135
pub struct NoSolution;
3236

src/librustc/traits/select.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ enum BuiltinImplConditions<'tcx> {
319319
/// all the "potential success" candidates can potentially succeed,
320320
/// so they are no-ops when unioned with a definite error, and within
321321
/// the categories it's easy to see that the unions are correct.
322-
enum EvaluationResult {
322+
pub enum EvaluationResult {
323323
/// Evaluation successful
324324
EvaluatedToOk,
325325
/// Evaluation is known to be ambiguous - it *might* hold for some
@@ -383,7 +383,7 @@ enum EvaluationResult {
383383
}
384384

385385
impl EvaluationResult {
386-
fn may_apply(self) -> bool {
386+
pub fn may_apply(self) -> bool {
387387
match self {
388388
EvaluatedToOk |
389389
EvaluatedToAmbig |
@@ -406,6 +406,14 @@ impl EvaluationResult {
406406
}
407407
}
408408

409+
impl_stable_hash_for!(enum self::EvaluationResult {
410+
EvaluatedToOk,
411+
EvaluatedToAmbig,
412+
EvaluatedToUnknown,
413+
EvaluatedToRecur,
414+
EvaluatedToErr
415+
});
416+
409417
#[derive(Clone)]
410418
pub struct EvaluationCache<'tcx> {
411419
hashmap: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>
@@ -574,6 +582,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
574582
})
575583
}
576584

585+
/// Evaluates whether the obligation `obligation` can be satisfied and returns
586+
/// an `EvaluationResult`.
587+
pub fn evaluate_obligation_recursively(&mut self,
588+
obligation: &PredicateObligation<'tcx>)
589+
-> EvaluationResult
590+
{
591+
self.probe(|this, _| {
592+
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
593+
})
594+
}
595+
577596
/// Evaluates the predicates in `predicates` recursively. Note that
578597
/// this applies projections in the predicates, and therefore
579598
/// is run within an inference probe.

src/librustc/ty/maps/config.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use dep_graph::SerializedDepNodeIndex;
1212
use hir::def_id::{CrateNum, DefId, DefIndex};
1313
use mir::interpret::{GlobalId};
14-
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
14+
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
1515
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
1616
use ty::subst::Substs;
1717
use ty::maps::queries;
@@ -73,6 +73,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_region
7373
}
7474
}
7575

76+
impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> {
77+
fn describe(_tcx: TyCtxt, goal: CanonicalPredicateGoal<'tcx>) -> String {
78+
format!("evaluating trait selection obligation `{:?}`", goal)
79+
}
80+
}
81+
7682
impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
7783
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
7884
format!("computing whether `{}` is `Copy`", env.value)

src/librustc/ty/maps/keys.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! Defines the set of legal keys that can be used in queries.
1212
1313
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
14-
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
14+
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
1515
use ty::{self, Ty, TyCtxt};
1616
use ty::subst::Substs;
1717
use ty::fast_reject::SimplifiedType;
@@ -191,3 +191,13 @@ impl<'tcx> Key for CanonicalTyGoal<'tcx> {
191191
DUMMY_SP
192192
}
193193
}
194+
195+
impl<'tcx> Key for CanonicalPredicateGoal<'tcx> {
196+
fn map_crate(&self) -> CrateNum {
197+
LOCAL_CRATE
198+
}
199+
200+
fn default_span(&self, _tcx: TyCtxt) -> Span {
201+
DUMMY_SP
202+
}
203+
}

src/librustc/ty/maps/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ use mir;
3333
use mir::interpret::{GlobalId};
3434
use session::{CompileResult, CrateDisambiguator};
3535
use session::config::OutputFilenames;
36-
use traits::Vtable;
37-
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
36+
use traits::{self, Vtable};
37+
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal,
38+
CanonicalTyGoal, NoSolution};
3839
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
3940
use traits::query::normalize::NormalizationResult;
4041
use traits::specialization_graph;
@@ -407,6 +408,11 @@ define_maps! { <'tcx>
407408
NoSolution,
408409
>,
409410

411+
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
412+
/// `infcx.predicate_must_hold()` instead.
413+
[] fn evaluate_obligation:
414+
EvaluateObligation(CanonicalPredicateGoal<'tcx>) -> traits::EvaluationResult,
415+
410416
[] fn substitute_normalize_and_test_predicates:
411417
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
412418

src/librustc/ty/maps/plumbing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
775775
DepKind::NormalizeProjectionTy |
776776
DepKind::NormalizeTyAfterErasingRegions |
777777
DepKind::DropckOutlives |
778+
DepKind::EvaluateObligation |
778779
DepKind::SubstituteNormalizeAndTestPredicates |
779780
DepKind::InstanceDefSizeEstimate |
780781

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::traits::{EvaluationResult, Obligation, ObligationCause, SelectionContext};
12+
use rustc::traits::query::CanonicalPredicateGoal;
13+
use rustc::ty::{ParamEnvAnd, TyCtxt};
14+
use syntax::codemap::DUMMY_SP;
15+
16+
crate fn evaluate_obligation<'tcx>(
17+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
18+
goal: CanonicalPredicateGoal<'tcx>,
19+
) -> EvaluationResult {
20+
tcx.infer_ctxt().enter(|ref infcx| {
21+
let (
22+
ParamEnvAnd {
23+
param_env,
24+
value: predicate,
25+
},
26+
_canonical_inference_vars,
27+
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
28+
29+
let mut selcx = SelectionContext::new(&infcx);
30+
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
31+
32+
selcx.evaluate_obligation_recursively(&obligation)
33+
})
34+
}

src/librustc_traits/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern crate syntax;
2626
extern crate syntax_pos;
2727

2828
mod dropck_outlives;
29+
mod evaluate_obligation;
2930
mod normalize_projection_ty;
3031
mod normalize_erasing_regions;
3132
mod util;
@@ -41,6 +42,7 @@ pub fn provide(p: &mut Providers) {
4142
normalize_ty_after_erasing_regions:
4243
normalize_erasing_regions::normalize_ty_after_erasing_regions,
4344
program_clauses_for: lowering::program_clauses_for,
45+
evaluate_obligation: evaluate_obligation::evaluate_obligation,
4446
..*p
4547
};
4648
}

0 commit comments

Comments
 (0)