Skip to content

Commit 8be066f

Browse files
committed
convert query-type-op to create query-region-constraint directly
1 parent dd96708 commit 8be066f

File tree

8 files changed

+179
-187
lines changed

8 files changed

+179
-187
lines changed

src/librustc/infer/canonical/query_result.rs

+46-39
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
//!
1818
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html
1919
20-
use either::Either;
2120
use infer::canonical::substitute::substitute_value;
2221
use infer::canonical::{
2322
Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty,
@@ -29,7 +28,6 @@ use rustc_data_structures::indexed_vec::Idx;
2928
use rustc_data_structures::indexed_vec::IndexVec;
3029
use rustc_data_structures::sync::Lrc;
3130
use std::fmt::Debug;
32-
use std::iter::once;
3331
use syntax::ast;
3432
use traits::query::NoSolution;
3533
use traits::{FulfillmentContext, TraitEngine};
@@ -191,9 +189,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
191189
pub fn instantiate_nll_query_result_and_region_obligations<R>(
192190
&self,
193191
cause: &ObligationCause<'tcx>,
192+
param_env: ty::ParamEnv<'tcx>,
194193
original_values: &CanonicalVarValues<'tcx>,
195194
query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
196-
) -> Vec<QueryRegionConstraint<'tcx>>
195+
output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>,
196+
) -> InferResult<'tcx, R>
197197
where
198198
R: Debug + TypeFoldable<'tcx>,
199199
{
@@ -210,52 +210,59 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
210210
// Compute `QueryRegionConstraint` values that unify each of
211211
// the original values `v_o` that was canonicalized into a
212212
// variable...
213-
let qrc_from_unify = original_values.var_values.iter_enumerated().flat_map(
214-
|(index, original_value)| {
215-
// ...with the value `v_r` of that variable from the query.
216-
let result_value =
217-
query_result
218-
.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]);
219-
match (original_value.unpack(), result_value.unpack()) {
220-
(
221-
UnpackedKind::Lifetime(ty::ReErased),
222-
UnpackedKind::Lifetime(ty::ReErased),
223-
) => {
224-
// no action needed
225-
Either::Left(None.into_iter())
226-
}
213+
let mut obligations = vec![];
214+
215+
for (index, original_value) in original_values.var_values.iter_enumerated() {
216+
// ...with the value `v_r` of that variable from the query.
217+
let result_value = query_result
218+
.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]);
219+
match (original_value.unpack(), result_value.unpack()) {
220+
(UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => {
221+
// no action needed
222+
}
227223

228-
(UnpackedKind::Lifetime(v_o), UnpackedKind::Lifetime(v_r)) => {
229-
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
230-
Either::Right(
231-
once(ty::OutlivesPredicate(v_o.into(), v_r))
232-
.chain(once(ty::OutlivesPredicate(v_r.into(), v_o)))
233-
.map(ty::Binder::dummy),
234-
)
224+
(UnpackedKind::Lifetime(v_o), UnpackedKind::Lifetime(v_r)) => {
225+
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
226+
if v_o != v_r {
227+
output_query_region_constraints
228+
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)));
229+
output_query_region_constraints
230+
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)));
235231
}
232+
}
236233

237-
(UnpackedKind::Type(_), _) | (_, UnpackedKind::Type(_)) => {
238-
// in NLL queries, we do not expect `type` results.
239-
bug!(
240-
"unexpected type in NLL query: cannot unify {:?} and {:?}",
241-
original_value,
242-
result_value,
243-
);
244-
}
234+
(UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
235+
let ok = self.at(cause, param_env).eq(v1, v2)?;
236+
obligations.extend(ok.into_obligations());
245237
}
246-
},
247-
);
238+
239+
_ => {
240+
bug!(
241+
"kind mismatch, cannot unify {:?} and {:?}",
242+
original_value,
243+
result_value
244+
);
245+
}
246+
}
247+
}
248248

249249
// ...also include the other query region constraints from the query.
250-
let qrc_from_result = query_result.value.region_constraints.iter().map(|r_c| {
251-
r_c.map_bound(|ty::OutlivesPredicate(k1, r2)| {
250+
output_query_region_constraints.reserve(query_result.value.region_constraints.len());
251+
for r_c in query_result.value.region_constraints.iter() {
252+
output_query_region_constraints.push(r_c.map_bound(|ty::OutlivesPredicate(k1, r2)| {
252253
let k1 = substitute_value(self.tcx, &result_subst, &k1);
253254
let r2 = substitute_value(self.tcx, &result_subst, &r2);
254255
ty::OutlivesPredicate(k1, r2)
255-
})
256-
});
256+
}));
257+
}
257258

258-
qrc_from_unify.chain(qrc_from_result).collect()
259+
let user_result: R =
260+
query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
261+
262+
Ok(InferOk {
263+
value: user_result,
264+
obligations,
265+
})
259266
}
260267

261268
/// Given the original values and the (canonicalized) result from

src/librustc/traits/query/type_op/custom.rs

+50-7
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@
99
// except according to those terms.
1010

1111
use infer::{InferCtxt, InferOk};
12-
use traits::query::Fallible;
13-
use ty::TyCtxt;
1412
use std::fmt;
13+
use traits::query::Fallible;
14+
15+
use infer::canonical::query_result;
16+
use infer::canonical::QueryRegionConstraint;
17+
use std::rc::Rc;
18+
use syntax::codemap::DUMMY_SP;
19+
use traits::{ObligationCause, TraitEngine};
1520

1621
pub struct CustomTypeOp<F, G> {
1722
closure: F,
@@ -38,12 +43,18 @@ where
3843
{
3944
type Output = R;
4045

41-
fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
42-
Err(self)
43-
}
46+
/// Processes the operation and all resulting obligations,
47+
/// returning the final result along with any region constraints
48+
/// (they will be given over to the NLL region solver).
49+
fn fully_perform(
50+
self,
51+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
52+
) -> Fallible<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
53+
if cfg!(debug_assertions) {
54+
info!("fully_perform({:?})", self);
55+
}
4456

45-
fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> Fallible<InferOk<'tcx, R>> {
46-
Ok((self.closure)(infcx)?)
57+
scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?))
4758
}
4859
}
4960

@@ -55,3 +66,35 @@ where
5566
write!(f, "{}", (self.description)())
5667
}
5768
}
69+
70+
/// Executes `op` and then scrapes out all the "old style" region
71+
/// constraints that result, creating query-region-constraints.
72+
fn scrape_region_constraints<'gcx, 'tcx, R>(
73+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
74+
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
75+
) -> Fallible<(R, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
76+
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
77+
let dummy_body_id = ObligationCause::dummy().body_id;
78+
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
79+
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
80+
fulfill_cx.register_predicate_obligations(infcx, obligations);
81+
if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
82+
infcx.tcx.sess.diagnostic().delay_span_bug(
83+
DUMMY_SP,
84+
&format!("errors selecting obligation during MIR typeck: {:?}", e),
85+
);
86+
}
87+
88+
let region_obligations = infcx.take_registered_region_obligations();
89+
90+
let region_constraint_data = infcx.take_and_reset_region_constraints();
91+
92+
let outlives =
93+
query_result::make_query_outlives(infcx.tcx, region_obligations, &region_constraint_data);
94+
95+
if outlives.is_empty() {
96+
Ok((value, None))
97+
} else {
98+
Ok((value, Some(Rc::new(outlives))))
99+
}
100+
}

src/librustc/traits/query/type_op/eq.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use infer::canonical::{Canonical, CanonicalizedQueryResult, QueryResult};
1212
use traits::query::Fallible;
13-
use ty::{self, ParamEnv, Ty, TyCtxt};
13+
use ty::{ParamEnv, Ty, TyCtxt};
1414

1515
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
1616
pub struct Eq<'tcx> {
@@ -29,20 +29,16 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> {
2929
type QueryKey = Self;
3030
type QueryResult = ();
3131

32-
fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::QueryResult, Self> {
32+
fn prequery(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::QueryResult, Self> {
3333
if self.a == self.b {
3434
Ok(())
3535
} else {
3636
Err(self)
3737
}
3838
}
3939

40-
fn into_query_key(self) -> Self {
41-
self
42-
}
43-
44-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
45-
self.param_env
40+
fn param_env(key: &Self::QueryKey) -> ParamEnv<'tcx> {
41+
key.param_env
4642
}
4743

4844
fn perform_query(

0 commit comments

Comments
 (0)