1 use crate::infer
::canonical
::{
2 Canonical
, Canonicalized
, CanonicalizedQueryResponse
, OriginalQueryValues
,
3 QueryRegionConstraint
, QueryResponse
,
5 use crate::infer
::{InferCtxt, InferOk}
;
8 use crate::traits
::query
::Fallible
;
9 use crate::traits
::ObligationCause
;
10 use crate::ty
::fold
::TypeFoldable
;
11 use crate::ty
::{Lift, ParamEnvAnd, TyCtxt}
;
13 pub mod ascribe_user_type
;
16 pub mod implied_outlives_bounds
;
19 pub mod prove_predicate
;
20 use self::prove_predicate
::ProvePredicate
;
23 /// "Type ops" are used in NLL to perform some particular action and
24 /// extract out the resulting region constraints (or an error if it
25 /// cannot be completed).
26 pub trait TypeOp
<'gcx
, 'tcx
>: Sized
+ fmt
::Debug
{
29 /// Processes the operation and all resulting obligations,
30 /// returning the final result along with any region constraints
31 /// (they will be given over to the NLL region solver).
34 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
35 ) -> Fallible
<(Self::Output
, Option
<Rc
<Vec
<QueryRegionConstraint
<'tcx
>>>>)>;
38 /// "Query type ops" are type ops that are implemented using a
39 /// [canonical query][c]. The `Self` type here contains the kernel of
40 /// information needed to do the operation -- `TypeOp` is actually
41 /// implemented for `ParamEnvAnd<Self>`, since we always need to bring
42 /// along a parameter environment as well. For query type-ops, we will
43 /// first canonicalize the key and then invoke the query on the tcx,
44 /// which produces the resulting query region constraints.
46 /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
47 pub trait QueryTypeOp
<'gcx
: 'tcx
, 'tcx
>:
48 fmt
::Debug
+ Sized
+ TypeFoldable
<'tcx
> + Lift
<'gcx
>
50 type QueryResponse
: TypeFoldable
<'tcx
> + Lift
<'gcx
>;
52 /// Give query the option for a simple fast path that never
53 /// actually hits the tcx cache lookup etc. Return `Some(r)` with
54 /// a final result or `None` to do the full path.
56 tcx
: TyCtxt
<'_
, 'gcx
, 'tcx
>,
57 key
: &ParamEnvAnd
<'tcx
, Self>,
58 ) -> Option
<Self::QueryResponse
>;
60 /// Performs the actual query with the canonicalized key -- the
61 /// real work happens here. This method is not given an `infcx`
62 /// because it shouldn't need one -- and if it had access to one,
63 /// it might do things like invoke `sub_regions`, which would be
64 /// bad, because it would create subregion relationships that are
65 /// not captured in the return value.
67 tcx
: TyCtxt
<'_
, 'gcx
, 'tcx
>,
68 canonicalized
: Canonicalized
<'gcx
, ParamEnvAnd
<'tcx
, Self>>,
69 ) -> Fallible
<CanonicalizedQueryResponse
<'gcx
, Self::QueryResponse
>>;
71 /// Casts a lifted query result (which is in the gcx lifetime)
72 /// into the tcx lifetime. This is always just an identity cast,
73 /// but the generic code doesn't realize it -- put another way, in
74 /// the generic code, we have a `Lifted<'gcx, Self::QueryResponse>`
75 /// and we want to convert that to a `Self::QueryResponse`. This is
76 /// not a priori valid, so we can't do it -- but in practice, it
77 /// is always a no-op (e.g., the lifted form of a type,
78 /// `Ty<'gcx>`, is a subtype of `Ty<'tcx>`). So we have to push
79 /// the operation into the impls that know more specifically what
80 /// `QueryResponse` is. This operation would (maybe) be nicer with
81 /// something like HKTs or GATs, since then we could make
82 /// `QueryResponse` parametric and `'gcx` and `'tcx` etc.
83 fn shrink_to_tcx_lifetime(
84 lifted_query_result
: &'a CanonicalizedQueryResponse
<'gcx
, Self::QueryResponse
>,
85 ) -> &'a Canonical
<'tcx
, QueryResponse
<'tcx
, Self::QueryResponse
>>;
87 fn fully_perform_into(
88 query_key
: ParamEnvAnd
<'tcx
, Self>,
89 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
90 output_query_region_constraints
: &mut Vec
<QueryRegionConstraint
<'tcx
>>,
91 ) -> Fallible
<Self::QueryResponse
> {
92 if let Some(result
) = QueryTypeOp
::try_fast_path(infcx
.tcx
, &query_key
) {
96 // FIXME(#33684) -- We need to use
97 // `canonicalize_hr_query_hack` here because of things
98 // like the subtype query, which go awry around
99 // `'static` otherwise.
100 let mut canonical_var_values
= OriginalQueryValues
::default();
102 infcx
.canonicalize_hr_query_hack(&query_key
, &mut canonical_var_values
);
103 let canonical_result
= Self::perform_query(infcx
.tcx
, canonical_self
)?
;
104 let canonical_result
= Self::shrink_to_tcx_lifetime(&canonical_result
);
106 let param_env
= query_key
.param_env
;
108 let InferOk { value, obligations }
= infcx
109 .instantiate_nll_query_response_and_region_obligations(
110 &ObligationCause
::dummy(),
112 &canonical_var_values
,
114 output_query_region_constraints
,
117 // Typically, instantiating NLL query results does not
118 // create obligations. However, in some cases there
119 // are unresolved type variables, and unify them *can*
120 // create obligations. In that case, we have to go
121 // fulfill them. We do this via a (recursive) query.
122 for obligation
in obligations
{
123 let () = ProvePredicate
::fully_perform_into(
126 .and(ProvePredicate
::new(obligation
.predicate
)),
128 output_query_region_constraints
,
136 impl<'gcx
: 'tcx
, 'tcx
, Q
> TypeOp
<'gcx
, 'tcx
> for ParamEnvAnd
<'tcx
, Q
>
138 Q
: QueryTypeOp
<'gcx
, 'tcx
>,
140 type Output
= Q
::QueryResponse
;
144 infcx
: &InferCtxt
<'_
, 'gcx
, 'tcx
>,
145 ) -> Fallible
<(Self::Output
, Option
<Rc
<Vec
<QueryRegionConstraint
<'tcx
>>>>)> {
146 let mut qrc
= vec
![];
147 let r
= Q
::fully_perform_into(self, infcx
, &mut qrc
)?
;
149 // Promote the final query-region-constraints into a
150 // (optional) ref-counted vector:
151 let opt_qrc
= if qrc
.is_empty() {