Skip to content

Commit 3bb15e5

Browse files
committed
introduce QueryTypeOp trait and use it for eq
1 parent 5673943 commit 3bb15e5

File tree

2 files changed

+107
-14
lines changed
  • src/librustc_mir/borrow_check/nll/type_check/type_op

2 files changed

+107
-14
lines changed

src/librustc_mir/borrow_check/nll/type_check/type_op/eq.rs

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use rustc::infer::{InferCtxt, InferResult};
12-
use rustc::traits::ObligationCause;
13-
use rustc::ty::{ParamEnv, Ty, TyCtxt};
11+
use rustc::infer::canonical::{CanonicalizedQueryResult, Canonical};
12+
use rustc::traits::query::NoSolution;
13+
use rustc::traits::{FulfillmentContext, ObligationCause};
14+
use rustc::ty::{self, ParamEnv, Ty, TyCtxt};
15+
use syntax::codemap::DUMMY_SP;
1416

15-
#[derive(Debug)]
17+
#[derive(Copy, Clone, Debug)]
1618
crate struct Eq<'tcx> {
1719
param_env: ParamEnv<'tcx>,
1820
a: Ty<'tcx>,
@@ -25,20 +27,55 @@ impl<'tcx> Eq<'tcx> {
2527
}
2628
}
2729

28-
impl<'gcx, 'tcx> super::TypeOp<'gcx, 'tcx> for Eq<'tcx> {
29-
type Output = ();
30+
impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> {
31+
type QueryResult = ();
3032

31-
fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
33+
fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::QueryResult, Self> {
3234
if self.a == self.b {
3335
Ok(())
3436
} else {
3537
Err(self)
3638
}
3739
}
3840

39-
fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
40-
infcx
41-
.at(&ObligationCause::dummy(), self.param_env)
42-
.eq(self.a, self.b)
41+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
42+
self.param_env
43+
}
44+
45+
fn perform_query(
46+
tcx: TyCtxt<'_, 'gcx, 'tcx>,
47+
canonicalized: Canonical<'gcx, Eq<'gcx>>,
48+
) -> CanonicalizedQueryResult<'gcx, ()> {
49+
let tcx = tcx.global_tcx();
50+
tcx.infer_ctxt()
51+
.enter(|ref infcx| {
52+
let (Eq { param_env, a, b }, canonical_inference_vars) =
53+
infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonicalized);
54+
let fulfill_cx = &mut FulfillmentContext::new();
55+
let obligations = match infcx.at(&ObligationCause::dummy(), param_env).eq(a, b) {
56+
Ok(v) => v.into_obligations(),
57+
Err(_) => return Err(NoSolution),
58+
};
59+
fulfill_cx.register_predicate_obligations(infcx, obligations);
60+
infcx.make_canonicalized_query_result(canonical_inference_vars, (), fulfill_cx)
61+
})
62+
.unwrap()
63+
}
64+
}
65+
66+
BraceStructTypeFoldableImpl! {
67+
impl<'tcx> TypeFoldable<'tcx> for Eq<'tcx> {
68+
param_env,
69+
a,
70+
b,
71+
}
72+
}
73+
74+
BraceStructLiftImpl! {
75+
impl<'a, 'tcx> Lift<'tcx> for Eq<'a> {
76+
type Lifted = Eq<'tcx>;
77+
param_env,
78+
a,
79+
b,
4380
}
4481
}

src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,21 @@
99
// except according to those terms.
1010

1111
use rustc::infer::canonical::query_result;
12-
use rustc::infer::canonical::QueryRegionConstraint;
12+
use rustc::infer::canonical::{Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint};
1313
use rustc::infer::{InferCtxt, InferOk, InferResult};
1414
use rustc::traits::{ObligationCause, TraitEngine};
1515
use rustc::ty::error::TypeError;
16-
use rustc::ty::TyCtxt;
16+
use rustc::ty::fold::TypeFoldable;
17+
use rustc::ty::{Lift, ParamEnv, TyCtxt};
1718
use std::fmt;
1819
use std::rc::Rc;
1920
use syntax::codemap::DUMMY_SP;
2021

2122
crate mod custom;
2223
crate mod eq;
2324
crate mod normalize;
24-
crate mod predicates;
2525
crate mod outlives;
26+
crate mod predicates;
2627
crate mod subtype;
2728

2829
crate trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
@@ -96,3 +97,58 @@ crate trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
9697
}
9798
}
9899
}
100+
101+
type Lifted<'gcx, T> = <T as Lift<'gcx>>::Lifted;
102+
103+
crate trait QueryTypeOp<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> {
104+
type QueryResult: TypeFoldable<'tcx> + Lift<'gcx>;
105+
106+
/// Micro-optimization: returns `Ok(x)` if we can trivially
107+
/// produce the output, else returns `Err(self)` back.
108+
fn trivial_noop(
109+
self,
110+
tcx: TyCtxt<'_, 'gcx, 'tcx>,
111+
) -> Result<Lifted<'gcx, Self::QueryResult>, Self>;
112+
113+
fn param_env(&self) -> ParamEnv<'tcx>;
114+
115+
fn perform_query(
116+
tcx: TyCtxt<'_, 'gcx, 'tcx>,
117+
canonicalized: Canonicalized<'gcx, Self>,
118+
) -> CanonicalizedQueryResult<'gcx, Self::QueryResult>;
119+
}
120+
121+
impl<'gcx: 'tcx, 'tcx, Q> TypeOp<'gcx, 'tcx> for Q
122+
where
123+
Q: QueryTypeOp<'gcx, 'tcx>,
124+
Lifted<'gcx, Q::QueryResult>: TypeFoldable<'tcx>,
125+
{
126+
type Output = Lifted<'gcx, Q::QueryResult>;
127+
128+
fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
129+
QueryTypeOp::trivial_noop(self, tcx)
130+
}
131+
132+
fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
133+
let param_env = self.param_env();
134+
135+
let (canonical_self, canonical_var_values) = infcx.canonicalize_query(&self);
136+
let canonical_result = Q::perform_query(infcx.tcx, canonical_self);
137+
138+
// FIXME: This is not the most efficient setup. The
139+
// `instantiate_query_result_and_region_obligations` basically
140+
// takes the `QueryRegionConstraint` values that we ultimately
141+
// want to use and converts them into obligations. We return
142+
// those to our caller, which will convert them into AST
143+
// region constraints; we then convert *those* back into
144+
// `QueryRegionConstraint` and ultimately into NLL
145+
// constraints. We should cut out the middleman but that will
146+
// take a bit of refactoring.
147+
infcx.instantiate_query_result_and_region_obligations(
148+
&ObligationCause::dummy(),
149+
param_env,
150+
&canonical_var_values,
151+
&canonical_result,
152+
)
153+
}
154+
}

0 commit comments

Comments
 (0)