Skip to content

Commit 3ab3a9f

Browse files
committed
Create a canonical trait query for evaluate_obligation
1 parent 79f71f9 commit 3ab3a9f

File tree

11 files changed

+155
-15
lines changed

11 files changed

+155
-15
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

@@ -643,6 +644,7 @@ define_dep_nodes!( <'tcx>
643644
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
644645
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
645646
[] DropckOutlives(CanonicalTyGoal<'tcx>),
647+
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
646648

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

src/librustc/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub use self::object_safety::ObjectSafetyViolation;
4141
pub use self::object_safety::MethodViolationCode;
4242
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
4343
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
44-
pub use self::select::IntercrateAmbiguityCause;
44+
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
4545
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
4646
pub use self::specialize::{SpecializesCache, find_associated_item};
4747
pub use self::engine::TraitEngine;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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, PredicateObligation};
14+
use traits::query::CanonicalPredicateGoal;
15+
use ty::{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+
obligation: &PredicateObligation<'tcx>,
23+
) -> bool {
24+
let (c_pred, _) =
25+
self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
26+
27+
self.tcx.global_tcx().evaluate_obligation(c_pred).may_apply()
28+
}
29+
30+
/// Evaluates whether the predicate can be satisfied in the given
31+
/// `ParamEnv`, and returns `false` if not certain. However, this is
32+
/// not entirely accurate if inference variables are involved.
33+
pub fn predicate_must_hold(
34+
&self,
35+
obligation: &PredicateObligation<'tcx>,
36+
) -> bool {
37+
let (c_pred, _) =
38+
self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
39+
40+
self.tcx.global_tcx().evaluate_obligation(c_pred) ==
41+
EvaluationResult::EvaluatedToOk
42+
}
43+
}
44+
45+
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> {
46+
type Canonicalized = CanonicalPredicateGoal<'gcx>;
47+
48+
fn intern(
49+
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
50+
value: Canonical<'gcx, Self::Lifted>,
51+
) -> Self::Canonicalized {
52+
value
53+
}
54+
}

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: 24 additions & 9 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
@@ -385,7 +385,7 @@ enum EvaluationResult {
385385
}
386386

387387
impl EvaluationResult {
388-
fn may_apply(self) -> bool {
388+
pub fn may_apply(self) -> bool {
389389
match self {
390390
EvaluatedToOk |
391391
EvaluatedToAmbig |
@@ -408,10 +408,18 @@ impl EvaluationResult {
408408
}
409409
}
410410

411+
impl_stable_hash_for!(enum self::EvaluationResult {
412+
EvaluatedToOk,
413+
EvaluatedToAmbig,
414+
EvaluatedToUnknown,
415+
EvaluatedToRecur,
416+
EvaluatedToErr
417+
});
418+
411419
#[derive(Clone, Debug, PartialEq, Eq)]
412420
/// Indicates that trait evaluation caused overflow. Stores the obligation
413421
/// that hit the recursion limit.
414-
pub struct OverflowError<'tcx>(TraitObligation<'tcx>);
422+
pub struct OverflowError<'tcx>(pub TraitObligation<'tcx>);
415423

416424
impl<'tcx> From<OverflowError<'tcx>> for SelectionError<'tcx> {
417425
fn from(OverflowError(o): OverflowError<'tcx>) -> SelectionError<'tcx> {
@@ -574,9 +582,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
574582
debug!("evaluate_obligation({:?})",
575583
obligation);
576584

577-
match self.probe(|this, _| {
578-
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
579-
}) {
585+
match self.evaluate_obligation_recursively(obligation) {
580586
Ok(result) => result.may_apply(),
581587
Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
582588
}
@@ -592,14 +598,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
592598
debug!("evaluate_obligation_conservatively({:?})",
593599
obligation);
594600

595-
match self.probe(|this, _| {
596-
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
597-
}) {
601+
match self.evaluate_obligation_recursively(obligation) {
598602
Ok(result) => result == EvaluatedToOk,
599603
Err(OverflowError(o)) => self.infcx().report_overflow_error(&o, true)
600604
}
601605
}
602606

607+
/// Evaluates whether the obligation `obligation` can be satisfied and returns
608+
/// an `EvaluationResult`.
609+
pub fn evaluate_obligation_recursively(&mut self,
610+
obligation: &PredicateObligation<'tcx>)
611+
-> Result<EvaluationResult, OverflowError<'tcx>>
612+
{
613+
self.probe(|this, _| {
614+
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
615+
})
616+
}
617+
603618
/// Evaluates the predicates in `predicates` recursively. Note that
604619
/// this applies projections in the predicates, and therefore
605620
/// 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.value.value)
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;
@@ -200,3 +200,13 @@ impl<'tcx> Key for CanonicalTyGoal<'tcx> {
200200
DUMMY_SP
201201
}
202202
}
203+
204+
impl<'tcx> Key for CanonicalPredicateGoal<'tcx> {
205+
fn map_crate(&self) -> CrateNum {
206+
LOCAL_CRATE
207+
}
208+
209+
fn default_span(&self, _tcx: TyCtxt) -> Span {
210+
DUMMY_SP
211+
}
212+
}

src/librustc/ty/maps/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ use mir;
3232
use mir::interpret::{GlobalId};
3333
use session::{CompileResult, CrateDisambiguator};
3434
use session::config::OutputFilenames;
35-
use traits::Vtable;
36-
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
35+
use traits::{self, Vtable};
36+
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal,
37+
CanonicalTyGoal, NoSolution};
3738
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
3839
use traits::query::normalize::NormalizationResult;
3940
use traits::specialization_graph;
@@ -433,6 +434,11 @@ define_maps! { <'tcx>
433434
NoSolution,
434435
>,
435436

437+
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
438+
/// `infcx.predicate_must_hold()` instead.
439+
[] fn evaluate_obligation:
440+
EvaluateObligation(CanonicalPredicateGoal<'tcx>) -> traits::EvaluationResult,
441+
436442
[] fn substitute_normalize_and_test_predicates:
437443
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
438444

src/librustc/ty/maps/plumbing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
977977
DepKind::NormalizeProjectionTy |
978978
DepKind::NormalizeTyAfterErasingRegions |
979979
DepKind::DropckOutlives |
980+
DepKind::EvaluateObligation |
980981
DepKind::SubstituteNormalizeAndTestPredicates |
981982
DepKind::InstanceDefSizeEstimate |
982983
DepKind::ProgramClausesForEnv |
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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,
12+
OverflowError, SelectionContext};
13+
use rustc::traits::query::CanonicalPredicateGoal;
14+
use rustc::ty::{ParamEnvAnd, TyCtxt};
15+
use syntax::codemap::DUMMY_SP;
16+
17+
crate fn evaluate_obligation<'tcx>(
18+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
19+
goal: CanonicalPredicateGoal<'tcx>,
20+
) -> EvaluationResult {
21+
tcx.infer_ctxt().enter(|ref infcx| {
22+
let (
23+
ParamEnvAnd {
24+
param_env,
25+
value: predicate,
26+
},
27+
_canonical_inference_vars,
28+
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
29+
30+
let mut selcx = SelectionContext::new(&infcx);
31+
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
32+
33+
match selcx.evaluate_obligation_recursively(&obligation) {
34+
Ok(result) => result,
35+
Err(OverflowError(o)) => {
36+
infcx.report_overflow_error(&o, true)
37+
}
38+
}
39+
})
40+
}

src/librustc_traits/lib.rs

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

2424
mod dropck_outlives;
25+
mod evaluate_obligation;
2526
mod normalize_projection_ty;
2627
mod normalize_erasing_regions;
2728
mod util;
@@ -38,6 +39,7 @@ pub fn provide(p: &mut Providers) {
3839
normalize_erasing_regions::normalize_ty_after_erasing_regions,
3940
program_clauses_for: lowering::program_clauses_for,
4041
program_clauses_for_env: lowering::program_clauses_for_env,
42+
evaluate_obligation: evaluate_obligation::evaluate_obligation,
4143
..*p
4244
};
4345
}

0 commit comments

Comments
 (0)