]> git.proxmox.com Git - rustc.git/blame - src/librustc/traits/query/type_op/mod.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / librustc / traits / query / type_op / mod.rs
CommitLineData
8faf50e0
XL
1// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
0bf4aa26
XL
11use infer::canonical::{
12 Canonical, Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues,
13 QueryRegionConstraint, QueryResponse,
14};
8faf50e0 15use infer::{InferCtxt, InferOk};
8faf50e0
XL
16use std::fmt;
17use std::rc::Rc;
18use traits::query::Fallible;
19use traits::ObligationCause;
20use ty::fold::TypeFoldable;
21use ty::{Lift, ParamEnvAnd, TyCtxt};
22
0bf4aa26 23pub mod ascribe_user_type;
8faf50e0
XL
24pub mod custom;
25pub mod eq;
b7449926 26pub mod implied_outlives_bounds;
8faf50e0
XL
27pub mod normalize;
28pub mod outlives;
29pub mod prove_predicate;
30use self::prove_predicate::ProvePredicate;
31pub mod subtype;
32
33/// "Type ops" are used in NLL to perform some particular action and
34/// extract out the resulting region constraints (or an error if it
35/// cannot be completed).
36pub trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
37 type Output;
38
39 /// Processes the operation and all resulting obligations,
40 /// returning the final result along with any region constraints
41 /// (they will be given over to the NLL region solver).
42 fn fully_perform(
43 self,
44 infcx: &InferCtxt<'_, 'gcx, 'tcx>,
45 ) -> Fallible<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)>;
46}
47
48/// "Query type ops" are type ops that are implemented using a
49/// [canonical query][c]. The `Self` type here contains the kernel of
50/// information needed to do the operation -- `TypeOp` is actually
51/// implemented for `ParamEnvAnd<Self>`, since we always need to bring
52/// along a parameter environment as well. For query type-ops, we will
53/// first canonicalize the key and then invoke the query on the tcx,
54/// which produces the resulting query region constraints.
55///
56/// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
57pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>:
58 fmt::Debug + Sized + TypeFoldable<'tcx> + Lift<'gcx>
59{
0bf4aa26 60 type QueryResponse: TypeFoldable<'tcx> + Lift<'gcx>;
8faf50e0
XL
61
62 /// Give query the option for a simple fast path that never
63 /// actually hits the tcx cache lookup etc. Return `Some(r)` with
64 /// a final result or `None` to do the full path.
65 fn try_fast_path(
66 tcx: TyCtxt<'_, 'gcx, 'tcx>,
67 key: &ParamEnvAnd<'tcx, Self>,
0bf4aa26 68 ) -> Option<Self::QueryResponse>;
8faf50e0
XL
69
70 /// Performs the actual query with the canonicalized key -- the
71 /// real work happens here. This method is not given an `infcx`
72 /// because it shouldn't need one -- and if it had access to one,
73 /// it might do things like invoke `sub_regions`, which would be
74 /// bad, because it would create subregion relationships that are
75 /// not captured in the return value.
76 fn perform_query(
77 tcx: TyCtxt<'_, 'gcx, 'tcx>,
78 canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
0bf4aa26 79 ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self::QueryResponse>>;
8faf50e0
XL
80
81 /// Casts a lifted query result (which is in the gcx lifetime)
82 /// into the tcx lifetime. This is always just an identity cast,
83 /// but the generic code doesn't realize it -- put another way, in
0bf4aa26
XL
84 /// the generic code, we have a `Lifted<'gcx, Self::QueryResponse>`
85 /// and we want to convert that to a `Self::QueryResponse`. This is
8faf50e0
XL
86 /// not a priori valid, so we can't do it -- but in practice, it
87 /// is always a no-op (e.g., the lifted form of a type,
88 /// `Ty<'gcx>`, is a subtype of `Ty<'tcx>`). So we have to push
89 /// the operation into the impls that know more specifically what
0bf4aa26 90 /// `QueryResponse` is. This operation would (maybe) be nicer with
8faf50e0 91 /// something like HKTs or GATs, since then we could make
0bf4aa26 92 /// `QueryResponse` parametric and `'gcx` and `'tcx` etc.
8faf50e0 93 fn shrink_to_tcx_lifetime(
0bf4aa26
XL
94 lifted_query_result: &'a CanonicalizedQueryResponse<'gcx, Self::QueryResponse>,
95 ) -> &'a Canonical<'tcx, QueryResponse<'tcx, Self::QueryResponse>>;
8faf50e0
XL
96
97 fn fully_perform_into(
98 query_key: ParamEnvAnd<'tcx, Self>,
99 infcx: &InferCtxt<'_, 'gcx, 'tcx>,
100 output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>,
0bf4aa26 101 ) -> Fallible<Self::QueryResponse> {
8faf50e0
XL
102 if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
103 return Ok(result);
104 }
105
106 // FIXME(#33684) -- We need to use
107 // `canonicalize_hr_query_hack` here because of things
108 // like the subtype query, which go awry around
109 // `'static` otherwise.
0bf4aa26 110 let mut canonical_var_values = OriginalQueryValues::default();
8faf50e0
XL
111 let canonical_self =
112 infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values);
113 let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
114 let canonical_result = Self::shrink_to_tcx_lifetime(&canonical_result);
115
116 let param_env = query_key.param_env;
117
118 let InferOk { value, obligations } = infcx
0bf4aa26 119 .instantiate_nll_query_response_and_region_obligations(
8faf50e0
XL
120 &ObligationCause::dummy(),
121 param_env,
122 &canonical_var_values,
123 canonical_result,
124 output_query_region_constraints,
125 )?;
126
127 // Typically, instantiating NLL query results does not
128 // create obligations. However, in some cases there
129 // are unresolved type variables, and unify them *can*
130 // create obligations. In that case, we have to go
131 // fulfill them. We do this via a (recursive) query.
132 for obligation in obligations {
133 let () = ProvePredicate::fully_perform_into(
134 obligation
135 .param_env
136 .and(ProvePredicate::new(obligation.predicate)),
137 infcx,
138 output_query_region_constraints,
139 )?;
140 }
141
142 Ok(value)
143 }
144}
145
146impl<'gcx: 'tcx, 'tcx, Q> TypeOp<'gcx, 'tcx> for ParamEnvAnd<'tcx, Q>
147where
148 Q: QueryTypeOp<'gcx, 'tcx>,
149{
0bf4aa26 150 type Output = Q::QueryResponse;
8faf50e0
XL
151
152 fn fully_perform(
153 self,
154 infcx: &InferCtxt<'_, 'gcx, 'tcx>,
155 ) -> Fallible<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
156 let mut qrc = vec![];
157 let r = Q::fully_perform_into(self, infcx, &mut qrc)?;
158
159 // Promote the final query-region-constraints into a
160 // (optional) ref-counted vector:
161 let opt_qrc = if qrc.is_empty() {
162 None
163 } else {
164 Some(Rc::new(qrc))
165 };
166
167 Ok((r, opt_qrc))
168 }
169}