|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 | 11 | use rustc::infer::canonical::query_result;
|
12 |
| -use rustc::infer::canonical::QueryRegionConstraint; |
| 12 | +use rustc::infer::canonical::{Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint}; |
13 | 13 | use rustc::infer::{InferCtxt, InferOk, InferResult};
|
14 | 14 | use rustc::traits::{ObligationCause, TraitEngine};
|
15 | 15 | use rustc::ty::error::TypeError;
|
16 |
| -use rustc::ty::TyCtxt; |
| 16 | +use rustc::ty::fold::TypeFoldable; |
| 17 | +use rustc::ty::{Lift, ParamEnv, TyCtxt}; |
17 | 18 | use std::fmt;
|
18 | 19 | use std::rc::Rc;
|
19 | 20 | use syntax::codemap::DUMMY_SP;
|
20 | 21 |
|
21 | 22 | crate mod custom;
|
22 | 23 | crate mod eq;
|
23 | 24 | crate mod normalize;
|
24 |
| -crate mod predicates; |
25 | 25 | crate mod outlives;
|
| 26 | +crate mod predicates; |
26 | 27 | crate mod subtype;
|
27 | 28 |
|
28 | 29 | crate trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
|
@@ -96,3 +97,58 @@ crate trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
|
96 | 97 | }
|
97 | 98 | }
|
98 | 99 | }
|
| 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