rustc_trait_selection/traits/query/type_op/
mod.rs1use std::fmt;
2
3use rustc_errors::ErrorGuaranteed;
4use rustc_infer::traits::PredicateObligations;
5use rustc_middle::traits::query::NoSolution;
6use rustc_middle::ty::{ParamEnvAnd, TyCtxt, TypeFoldable};
7use rustc_span::Span;
8
9use crate::infer::canonical::{
10 CanonicalQueryInput, CanonicalQueryResponse, Certainty, OriginalQueryValues,
11 QueryRegionConstraints,
12};
13use crate::infer::{InferCtxt, InferOk};
14use crate::traits::{ObligationCause, ObligationCtxt};
15
16pub mod ascribe_user_type;
17pub mod custom;
18pub mod implied_outlives_bounds;
19pub mod normalize;
20pub mod outlives;
21pub mod prove_predicate;
22
23pub use rustc_middle::traits::query::type_op::*;
24
25use self::custom::scrape_region_constraints;
26
27pub trait TypeOp<'tcx>: Sized + fmt::Debug {
31 type Output: fmt::Debug;
32 type ErrorInfo;
33
34 fn fully_perform(
38 self,
39 infcx: &InferCtxt<'tcx>,
40 span: Span,
41 ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed>;
42}
43
44pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
46 pub output: Op::Output,
48 pub constraints: Option<&'tcx QueryRegionConstraints<'tcx>>,
50 pub error_info: Option<Op::ErrorInfo>,
52}
53
54pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 'tcx {
64 type QueryResponse: TypeFoldable<TyCtxt<'tcx>>;
65
66 fn try_fast_path(
70 tcx: TyCtxt<'tcx>,
71 key: &ParamEnvAnd<'tcx, Self>,
72 ) -> Option<Self::QueryResponse>;
73
74 fn perform_query(
81 tcx: TyCtxt<'tcx>,
82 canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
83 ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution>;
84
85 fn perform_locally_with_next_solver(
92 ocx: &ObligationCtxt<'_, 'tcx>,
93 key: ParamEnvAnd<'tcx, Self>,
94 span: Span,
95 ) -> Result<Self::QueryResponse, NoSolution>;
96
97 fn fully_perform_into(
98 query_key: ParamEnvAnd<'tcx, Self>,
99 infcx: &InferCtxt<'tcx>,
100 output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
101 span: Span,
102 ) -> Result<
103 (
104 Self::QueryResponse,
105 Option<CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>>,
106 PredicateObligations<'tcx>,
107 Certainty,
108 ),
109 NoSolution,
110 > {
111 if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
112 return Ok((result, None, PredicateObligations::new(), Certainty::Proven));
113 }
114
115 let mut canonical_var_values = OriginalQueryValues::default();
116 let old_param_env = query_key.param_env;
117 let canonical_self = infcx.canonicalize_query(query_key, &mut canonical_var_values);
118 let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
119
120 let InferOk { value, obligations } = infcx
121 .instantiate_nll_query_response_and_region_obligations(
122 &ObligationCause::dummy_with_span(span),
123 old_param_env,
124 &canonical_var_values,
125 canonical_result,
126 output_query_region_constraints,
127 )?;
128
129 Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
130 }
131}
132
133impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
134where
135 Q: QueryTypeOp<'tcx>,
136{
137 type Output = Q::QueryResponse;
138 type ErrorInfo = CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Q>>;
139
140 fn fully_perform(
141 self,
142 infcx: &InferCtxt<'tcx>,
143 span: Span,
144 ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
145 if infcx.next_trait_solver() {
153 return Ok(scrape_region_constraints(
154 infcx,
155 |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span),
156 "query type op",
157 span,
158 )?
159 .0);
160 }
161
162 let mut error_info = None;
163 let mut region_constraints = QueryRegionConstraints::default();
164
165 let (mut output, _) = scrape_region_constraints(
170 infcx,
171 |ocx| {
172 let (output, ei, obligations, _) =
173 Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
174 error_info = ei;
175
176 ocx.register_obligations(obligations);
177 Ok(output)
178 },
179 "fully_perform",
180 span,
181 )?;
182 output.error_info = error_info;
183 if let Some(QueryRegionConstraints { outlives }) = output.constraints {
184 region_constraints.outlives.extend(outlives.iter().cloned());
185 }
186 output.constraints = if region_constraints.is_empty() {
187 None
188 } else {
189 Some(infcx.tcx.arena.alloc(region_constraints))
190 };
191 Ok(output)
192 }
193}