1 use crate::infer
::canonical
::{
2 Canonicalized
, CanonicalizedQueryResponse
, OriginalQueryValues
, QueryRegionConstraints
,
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}
;
12 pub mod ascribe_user_type
;
15 pub mod implied_outlives_bounds
;
18 pub mod prove_predicate
;
19 use self::prove_predicate
::ProvePredicate
;
22 pub use rustc_middle
::traits
::query
::type_op
::*;
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
{
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).
35 infcx
: &InferCtxt
<'_
, 'tcx
>,
36 ) -> Fallible
<(Self::Output
, Option
<Rc
<QueryRegionConstraints
<'tcx
>>>)>;
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.
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
>;
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.
56 key
: &ParamEnvAnd
<'tcx
, Self>,
57 ) -> Option
<Self::QueryResponse
>;
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.
67 canonicalized
: Canonicalized
<'tcx
, ParamEnvAnd
<'tcx
, Self>>,
68 ) -> Fallible
<CanonicalizedQueryResponse
<'tcx
, Self::QueryResponse
>>;
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
) {
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();
85 infcx
.canonicalize_hr_query_hack(&query_key
, &mut canonical_var_values
);
86 let canonical_result
= Self::perform_query(infcx
.tcx
, canonical_self
)?
;
88 let param_env
= query_key
.param_env
;
90 let InferOk { value, obligations }
= infcx
91 .instantiate_nll_query_response_and_region_obligations(
92 &ObligationCause
::dummy(),
94 &canonical_var_values
,
96 output_query_region_constraints
,
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
)),
108 output_query_region_constraints
,
116 impl<'tcx
, Q
> TypeOp
<'tcx
> for ParamEnvAnd
<'tcx
, Q
>
118 Q
: QueryTypeOp
<'tcx
>,
120 type Output
= Q
::QueryResponse
;
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
)?
;
129 // Promote the final query-region-constraints into a
130 // (optional) ref-counted vector:
132 if region_constraints
.is_empty() { None }
else { Some(Rc::new(region_constraints)) }
;