]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::infer::canonical::{ |
dfeec247 | 2 | Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints, |
0bf4aa26 | 3 | }; |
9fa01778 | 4 | use crate::infer::{InferCtxt, InferOk}; |
9fa01778 XL |
5 | use crate::traits::query::Fallible; |
6 | use crate::traits::ObligationCause; | |
74b04a01 XL |
7 | use rustc::ty::fold::TypeFoldable; |
8 | use rustc::ty::{ParamEnvAnd, TyCtxt}; | |
dfeec247 XL |
9 | use std::fmt; |
10 | use std::rc::Rc; | |
8faf50e0 | 11 | |
0bf4aa26 | 12 | pub mod ascribe_user_type; |
8faf50e0 XL |
13 | pub mod custom; |
14 | pub mod eq; | |
b7449926 | 15 | pub mod implied_outlives_bounds; |
8faf50e0 XL |
16 | pub mod normalize; |
17 | pub mod outlives; | |
18 | pub mod prove_predicate; | |
19 | use self::prove_predicate::ProvePredicate; | |
20 | pub mod subtype; | |
21 | ||
74b04a01 XL |
22 | pub use rustc::traits::query::type_op::*; |
23 | ||
8faf50e0 XL |
24 | /// "Type ops" are used in NLL to perform some particular action and |
25 | /// extract out the resulting region constraints (or an error if it | |
26 | /// cannot be completed). | |
dc9dc135 | 27 | pub trait TypeOp<'tcx>: Sized + fmt::Debug { |
8faf50e0 XL |
28 | type Output; |
29 | ||
30 | /// Processes the operation and all resulting obligations, | |
31 | /// returning the final result along with any region constraints | |
32 | /// (they will be given over to the NLL region solver). | |
33 | fn fully_perform( | |
34 | self, | |
dc9dc135 XL |
35 | infcx: &InferCtxt<'_, 'tcx>, |
36 | ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>; | |
8faf50e0 XL |
37 | } |
38 | ||
39 | /// "Query type ops" are type ops that are implemented using a | |
40 | /// [canonical query][c]. The `Self` type here contains the kernel of | |
41 | /// information needed to do the operation -- `TypeOp` is actually | |
42 | /// implemented for `ParamEnvAnd<Self>`, since we always need to bring | |
43 | /// along a parameter environment as well. For query type-ops, we will | |
44 | /// first canonicalize the key and then invoke the query on the tcx, | |
45 | /// which produces the resulting query region constraints. | |
46 | /// | |
a1dfa0c6 | 47 | /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html |
dc9dc135 XL |
48 | pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { |
49 | type QueryResponse: TypeFoldable<'tcx>; | |
8faf50e0 XL |
50 | |
51 | /// Give query the option for a simple fast path that never | |
52 | /// actually hits the tcx cache lookup etc. Return `Some(r)` with | |
53 | /// a final result or `None` to do the full path. | |
54 | fn try_fast_path( | |
dc9dc135 | 55 | tcx: TyCtxt<'tcx>, |
8faf50e0 | 56 | key: &ParamEnvAnd<'tcx, Self>, |
0bf4aa26 | 57 | ) -> Option<Self::QueryResponse>; |
8faf50e0 XL |
58 | |
59 | /// Performs the actual query with the canonicalized key -- the | |
60 | /// real work happens here. This method is not given an `infcx` | |
61 | /// because it shouldn't need one -- and if it had access to one, | |
62 | /// it might do things like invoke `sub_regions`, which would be | |
63 | /// bad, because it would create subregion relationships that are | |
64 | /// not captured in the return value. | |
65 | fn perform_query( | |
dc9dc135 XL |
66 | tcx: TyCtxt<'tcx>, |
67 | canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, | |
68 | ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>; | |
8faf50e0 | 69 | |
8faf50e0 XL |
70 | fn fully_perform_into( |
71 | query_key: ParamEnvAnd<'tcx, Self>, | |
dc9dc135 XL |
72 | infcx: &InferCtxt<'_, 'tcx>, |
73 | output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, | |
0bf4aa26 | 74 | ) -> Fallible<Self::QueryResponse> { |
8faf50e0 XL |
75 | if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { |
76 | return Ok(result); | |
77 | } | |
78 | ||
79 | // FIXME(#33684) -- We need to use | |
80 | // `canonicalize_hr_query_hack` here because of things | |
81 | // like the subtype query, which go awry around | |
82 | // `'static` otherwise. | |
0bf4aa26 | 83 | let mut canonical_var_values = OriginalQueryValues::default(); |
8faf50e0 XL |
84 | let canonical_self = |
85 | infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); | |
86 | let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; | |
8faf50e0 XL |
87 | |
88 | let param_env = query_key.param_env; | |
89 | ||
90 | let InferOk { value, obligations } = infcx | |
0bf4aa26 | 91 | .instantiate_nll_query_response_and_region_obligations( |
8faf50e0 XL |
92 | &ObligationCause::dummy(), |
93 | param_env, | |
94 | &canonical_var_values, | |
95 | canonical_result, | |
96 | output_query_region_constraints, | |
97 | )?; | |
98 | ||
99 | // Typically, instantiating NLL query results does not | |
100 | // create obligations. However, in some cases there | |
101 | // are unresolved type variables, and unify them *can* | |
102 | // create obligations. In that case, we have to go | |
103 | // fulfill them. We do this via a (recursive) query. | |
104 | for obligation in obligations { | |
105 | let () = ProvePredicate::fully_perform_into( | |
dfeec247 | 106 | obligation.param_env.and(ProvePredicate::new(obligation.predicate)), |
8faf50e0 XL |
107 | infcx, |
108 | output_query_region_constraints, | |
109 | )?; | |
110 | } | |
111 | ||
112 | Ok(value) | |
113 | } | |
114 | } | |
115 | ||
dc9dc135 | 116 | impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q> |
8faf50e0 | 117 | where |
dc9dc135 | 118 | Q: QueryTypeOp<'tcx>, |
8faf50e0 | 119 | { |
0bf4aa26 | 120 | type Output = Q::QueryResponse; |
8faf50e0 XL |
121 | |
122 | fn fully_perform( | |
123 | self, | |
dc9dc135 XL |
124 | infcx: &InferCtxt<'_, 'tcx>, |
125 | ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> { | |
126 | let mut region_constraints = QueryRegionConstraints::default(); | |
127 | let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?; | |
8faf50e0 XL |
128 | |
129 | // Promote the final query-region-constraints into a | |
130 | // (optional) ref-counted vector: | |
dfeec247 XL |
131 | let opt_qrc = |
132 | if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; | |
8faf50e0 XL |
133 | |
134 | Ok((r, opt_qrc)) | |
135 | } | |
136 | } |