diff options
| -rw-r--r-- | src/Cargo.lock | 1 | ||||
| -rw-r--r-- | src/librustc/Cargo.toml | 1 | ||||
| -rw-r--r-- | src/librustc/infer/canonical/query_result.rs | 86 | ||||
| -rw-r--r-- | src/librustc/lib.rs | 1 |
4 files changed, 87 insertions, 2 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock index b74587e5662..f8551dffcf4 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1781,6 +1781,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 457a9f2f625..542ee9f02c9 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } bitflags = "1.0" +either = "1.5.0" fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } jobserver = "0.1" diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs index 71cefda6b66..d512bb5268d 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_result.rs @@ -17,10 +17,11 @@ //! //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html +use either::Either; use infer::canonical::substitute::substitute_value; use infer::canonical::{ - Canonical, CanonicalVarValues, CanonicalizedQueryResult, Certainty, QueryRegionConstraint, - QueryResult, + Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty, + QueryRegionConstraint, QueryResult, }; use infer::region_constraints::{Constraint, RegionConstraintData}; use infer::{InferCtxt, InferOk, InferResult, RegionObligation}; @@ -28,6 +29,7 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::sync::Lrc; use std::fmt::Debug; +use std::iter::once; use syntax::ast; use traits::query::NoSolution; use traits::{FulfillmentContext, TraitEngine}; @@ -176,6 +178,86 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { }) } + /// NLL does a lot of queries that have a particular form that we + /// can take advantage of to be more efficient. These queries do + /// not have any *type* inference variables, only region inference + /// variables. Therefore, when we instantiate the query result, we + /// only ever produce new *region constraints* and never other + /// forms of obligations (moreover, since we only determine + /// satisfiability modulo region constraints, instantiation is + /// infallible). Therefore, the return value need only be a larger + /// set of query region constraints. These constraints can then be + /// added directly to the NLL inference context. + pub fn instantiate_nll_query_result_and_region_obligations<R>( + &self, + cause: &ObligationCause<'tcx>, + original_values: &CanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + ) -> Vec<QueryRegionConstraint<'tcx>> + where + R: Debug + TypeFoldable<'tcx>, + { + // In an NLL query, there should be no type variables in the + // query, only region variables. + debug_assert!(query_result.variables.iter().all(|v| match v.kind { + CanonicalVarKind::Ty(_) => false, + CanonicalVarKind::Region => true, + })); + + let result_subst = + self.query_result_substitution_guess(cause, original_values, query_result); + + // Compute `QueryRegionConstraint` values that unify each of + // the original values `v_o` that was canonicalized into a + // variable... + let qrc_from_unify = original_values.var_values.iter_enumerated().flat_map( + |(index, original_value)| { + // ...with the value `v_r` of that variable from the query. + let result_value = + query_result + .substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]); + match (original_value.unpack(), result_value.unpack()) { + ( + UnpackedKind::Lifetime(ty::ReErased), + UnpackedKind::Lifetime(ty::ReErased), + ) => { + // no action needed + Either::Left(None.into_iter()) + } + + (UnpackedKind::Lifetime(v_o), UnpackedKind::Lifetime(v_r)) => { + // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. + Either::Right( + once(ty::OutlivesPredicate(v_o.into(), v_r)) + .chain(once(ty::OutlivesPredicate(v_r.into(), v_o))) + .map(ty::Binder::dummy), + ) + } + + (UnpackedKind::Type(_), _) | (_, UnpackedKind::Type(_)) => { + // in NLL queries, we do not expect `type` results. + bug!( + "unexpected type in NLL query: cannot unify {:?} and {:?}", + original_value, + result_value, + ); + } + } + }, + ); + + // ...also include the other query region constraints from the query. + let qrc_from_result = query_result.value.region_constraints.iter().map(|r_c| { + r_c.map_bound(|ty::OutlivesPredicate(k1, r2)| { + let k1 = substitute_value(self.tcx, &result_subst, &k1); + let r2 = substitute_value(self.tcx, &result_subst, &r2); + ty::OutlivesPredicate(k1, r2) + }) + }); + + qrc_from_unify.chain(qrc_from_result).collect() + } + /// Given the original values and the (canonicalized) result from /// computing a query, returns a substitution that can be applied /// to the query result to convert the result back into the diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 102efe2bef3..7c3d3414846 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -79,6 +79,7 @@ extern crate arena; #[macro_use] extern crate bitflags; extern crate core; +extern crate either; extern crate fmt_macros; extern crate getopts; extern crate graphviz; |
