]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / query / type_op / mod.rs
1 use crate::infer::canonical::{
2 Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints,
3 };
4 use crate::infer::{InferCtxt, InferOk};
5 use crate::traits::query::Fallible;
6 use crate::traits::ObligationCause;
7 use rustc_middle::ty::fold::TypeFoldable;
8 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
9 use std::fmt;
10 use std::rc::Rc;
11
12 pub mod ascribe_user_type;
13 pub mod custom;
14 pub mod eq;
15 pub mod implied_outlives_bounds;
16 pub mod normalize;
17 pub mod outlives;
18 pub mod prove_predicate;
19 use self::prove_predicate::ProvePredicate;
20 pub mod subtype;
21
22 pub use rustc_middle::traits::query::type_op::*;
23
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).
27 pub trait TypeOp<'tcx>: Sized + fmt::Debug {
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,
35 infcx: &InferCtxt<'_, 'tcx>,
36 ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>;
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 ///
47 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
48 pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
49 type QueryResponse: TypeFoldable<'tcx>;
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(
55 tcx: TyCtxt<'tcx>,
56 key: &ParamEnvAnd<'tcx, Self>,
57 ) -> Option<Self::QueryResponse>;
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(
66 tcx: TyCtxt<'tcx>,
67 canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
68 ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>;
69
70 fn fully_perform_into(
71 query_key: ParamEnvAnd<'tcx, Self>,
72 infcx: &InferCtxt<'_, 'tcx>,
73 output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
74 ) -> Fallible<Self::QueryResponse> {
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.
83 let mut canonical_var_values = OriginalQueryValues::default();
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)?;
87
88 let param_env = query_key.param_env;
89
90 let InferOk { value, obligations } = infcx
91 .instantiate_nll_query_response_and_region_obligations(
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(
106 obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
107 infcx,
108 output_query_region_constraints,
109 )?;
110 }
111
112 Ok(value)
113 }
114 }
115
116 impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
117 where
118 Q: QueryTypeOp<'tcx>,
119 {
120 type Output = Q::QueryResponse;
121
122 fn fully_perform(
123 self,
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)?;
128
129 // Promote the final query-region-constraints into a
130 // (optional) ref-counted vector:
131 let opt_qrc =
132 if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) };
133
134 Ok((r, opt_qrc))
135 }
136 }