Skip to content

Commit dd96708

Browse files
committed
add a streamlined instantiate_query_result method for NLL queries
1 parent 56e7587 commit dd96708

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

src/Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,7 @@ dependencies = [
17811781
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
17821782
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
17831783
"chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
1784+
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
17841785
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
17851786
"fmt_macros 0.0.0",
17861787
"graphviz 0.0.0",

src/librustc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ crate-type = ["dylib"]
1111
[dependencies]
1212
arena = { path = "../libarena" }
1313
bitflags = "1.0"
14+
either = "1.5.0"
1415
fmt_macros = { path = "../libfmt_macros" }
1516
graphviz = { path = "../libgraphviz" }
1617
jobserver = "0.1"

src/librustc/infer/canonical/query_result.rs

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@
1717
//!
1818
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html
1919
20+
use either::Either;
2021
use infer::canonical::substitute::substitute_value;
2122
use infer::canonical::{
22-
Canonical, CanonicalVarValues, CanonicalizedQueryResult, Certainty, QueryRegionConstraint,
23-
QueryResult,
23+
Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty,
24+
QueryRegionConstraint, QueryResult,
2425
};
2526
use infer::region_constraints::{Constraint, RegionConstraintData};
2627
use infer::{InferCtxt, InferOk, InferResult, RegionObligation};
2728
use rustc_data_structures::indexed_vec::Idx;
2829
use rustc_data_structures::indexed_vec::IndexVec;
2930
use rustc_data_structures::sync::Lrc;
3031
use std::fmt::Debug;
32+
use std::iter::once;
3133
use syntax::ast;
3234
use traits::query::NoSolution;
3335
use traits::{FulfillmentContext, TraitEngine};
@@ -176,6 +178,86 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
176178
})
177179
}
178180

181+
/// NLL does a lot of queries that have a particular form that we
182+
/// can take advantage of to be more efficient. These queries do
183+
/// not have any *type* inference variables, only region inference
184+
/// variables. Therefore, when we instantiate the query result, we
185+
/// only ever produce new *region constraints* and never other
186+
/// forms of obligations (moreover, since we only determine
187+
/// satisfiability modulo region constraints, instantiation is
188+
/// infallible). Therefore, the return value need only be a larger
189+
/// set of query region constraints. These constraints can then be
190+
/// added directly to the NLL inference context.
191+
pub fn instantiate_nll_query_result_and_region_obligations<R>(
192+
&self,
193+
cause: &ObligationCause<'tcx>,
194+
original_values: &CanonicalVarValues<'tcx>,
195+
query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
196+
) -> Vec<QueryRegionConstraint<'tcx>>
197+
where
198+
R: Debug + TypeFoldable<'tcx>,
199+
{
200+
// In an NLL query, there should be no type variables in the
201+
// query, only region variables.
202+
debug_assert!(query_result.variables.iter().all(|v| match v.kind {
203+
CanonicalVarKind::Ty(_) => false,
204+
CanonicalVarKind::Region => true,
205+
}));
206+
207+
let result_subst =
208+
self.query_result_substitution_guess(cause, original_values, query_result);
209+
210+
// Compute `QueryRegionConstraint` values that unify each of
211+
// the original values `v_o` that was canonicalized into a
212+
// 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+
}
227+
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+
)
235+
}
236+
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+
}
245+
}
246+
},
247+
);
248+
249+
// ...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)| {
252+
let k1 = substitute_value(self.tcx, &result_subst, &k1);
253+
let r2 = substitute_value(self.tcx, &result_subst, &r2);
254+
ty::OutlivesPredicate(k1, r2)
255+
})
256+
});
257+
258+
qrc_from_unify.chain(qrc_from_result).collect()
259+
}
260+
179261
/// Given the original values and the (canonicalized) result from
180262
/// computing a query, returns a substitution that can be applied
181263
/// to the query result to convert the result back into the

src/librustc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
extern crate arena;
8080
#[macro_use] extern crate bitflags;
8181
extern crate core;
82+
extern crate either;
8283
extern crate fmt_macros;
8384
extern crate getopts;
8485
extern crate graphviz;

0 commit comments

Comments
 (0)