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