]> git.proxmox.com Git - rustc.git/blame - src/librustc_infer/traits/query/type_op/mod.rs
New upstream version 1.43.0+dfsg1
[rustc.git] / src / librustc_infer / traits / query / type_op / mod.rs
CommitLineData
9fa01778 1use crate::infer::canonical::{
dfeec247 2 Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints,
0bf4aa26 3};
9fa01778 4use crate::infer::{InferCtxt, InferOk};
9fa01778
XL
5use crate::traits::query::Fallible;
6use crate::traits::ObligationCause;
74b04a01
XL
7use rustc::ty::fold::TypeFoldable;
8use rustc::ty::{ParamEnvAnd, TyCtxt};
dfeec247
XL
9use std::fmt;
10use std::rc::Rc;
8faf50e0 11
0bf4aa26 12pub mod ascribe_user_type;
8faf50e0
XL
13pub mod custom;
14pub mod eq;
b7449926 15pub mod implied_outlives_bounds;
8faf50e0
XL
16pub mod normalize;
17pub mod outlives;
18pub mod prove_predicate;
19use self::prove_predicate::ProvePredicate;
20pub mod subtype;
21
74b04a01
XL
22pub 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 27pub 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
48pub 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 116impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
8faf50e0 117where
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}