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 let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
114 return Ok((result, None, PredicateObligations::new(), Certainty::Proven));
115 }
116
117 let mut canonical_var_values = OriginalQueryValues::default();
118 let old_param_env = query_key.param_env;
119 let canonical_self = infcx.canonicalize_query(query_key, &mut canonical_var_values);
120 let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
121
122 let InferOk { value, obligations } = infcx
123 .instantiate_nll_query_response_and_region_obligations(
124 &ObligationCause::dummy_with_span(span),
125 old_param_env,
126 &canonical_var_values,
127 canonical_result,
128 output_query_region_constraints,
129 )?;
130
131 Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
132 }
133}
134
135impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
136where
137 Q: QueryTypeOp<'tcx>,
138{
139 type Output = Q::QueryResponse;
140 type ErrorInfo = CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Q>>;
141
142 fn fully_perform(
143 self,
144 infcx: &InferCtxt<'tcx>,
145 root_def_id: LocalDefId,
146 span: Span,
147 ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
148 if infcx.next_trait_solver() {
156 return Ok(scrape_region_constraints(
157 infcx,
158 root_def_id,
159 "query type op",
160 span,
161 |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span),
162 )?
163 .0);
164 }
165
166 let mut error_info = None;
167 let mut region_constraints = QueryRegionConstraints::default();
168
169 let (mut output, _) =
174 scrape_region_constraints(infcx, root_def_id, "fully_perform", span, |ocx| {
175 let (output, ei, obligations, _) =
176 Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
177 error_info = ei;
178
179 ocx.register_obligations(obligations);
180 Ok(output)
181 })?;
182 output.error_info = error_info;
183 if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints {
184 region_constraints.outlives.extend(outlives.iter().cloned());
185 region_constraints.assumptions.extend(assumptions.iter().cloned());
186 }
187 output.constraints = if region_constraints.is_empty() {
188 None
189 } else {
190 Some(infcx.tcx.arena.alloc(region_constraints))
191 };
192 Ok(output)
193 }
194}