]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / query / type_op / mod.rs
CommitLineData
9fa01778 1use crate::infer::canonical::{
9c376795 2 Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
0bf4aa26 3};
9fa01778 4use crate::infer::{InferCtxt, InferOk};
49aad941
FG
5use crate::traits::{ObligationCause, ObligationCtxt};
6use rustc_errors::ErrorGuaranteed;
9c376795 7use rustc_infer::infer::canonical::Certainty;
5099ac24 8use rustc_infer::traits::PredicateObligations;
49aad941 9use rustc_middle::traits::query::NoSolution;
ba9703b0
XL
10use rustc_middle::ty::fold::TypeFoldable;
11use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
49aad941 12use rustc_span::Span;
dfeec247 13use std::fmt;
8faf50e0 14
0bf4aa26 15pub mod ascribe_user_type;
8faf50e0
XL
16pub mod custom;
17pub mod eq;
b7449926 18pub mod implied_outlives_bounds;
8faf50e0
XL
19pub mod normalize;
20pub mod outlives;
21pub mod prove_predicate;
8faf50e0
XL
22pub mod subtype;
23
ba9703b0 24pub use rustc_middle::traits::query::type_op::*;
74b04a01 25
49aad941
FG
26use self::custom::scrape_region_constraints;
27
8faf50e0
XL
28/// "Type ops" are used in NLL to perform some particular action and
29/// extract out the resulting region constraints (or an error if it
30/// cannot be completed).
dc9dc135 31pub trait TypeOp<'tcx>: Sized + fmt::Debug {
f2b60f7d 32 type Output: fmt::Debug;
5e7ed085 33 type ErrorInfo;
8faf50e0
XL
34
35 /// Processes the operation and all resulting obligations,
36 /// returning the final result along with any region constraints
37 /// (they will be given over to the NLL region solver).
49aad941
FG
38 fn fully_perform(
39 self,
40 infcx: &InferCtxt<'tcx>,
41 span: Span,
42 ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed>;
94222f64
XL
43}
44
45/// The output from performing a type op
46pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
47 /// The output from the type op.
48 pub output: Op::Output,
49 /// Any region constraints from performing the type op.
064997fb 50 pub constraints: Option<&'tcx QueryRegionConstraints<'tcx>>,
5e7ed085
FG
51 /// Used for error reporting to be able to rerun the query
52 pub error_info: Option<Op::ErrorInfo>,
8faf50e0
XL
53}
54
55/// "Query type ops" are type ops that are implemented using a
56/// [canonical query][c]. The `Self` type here contains the kernel of
57/// information needed to do the operation -- `TypeOp` is actually
58/// implemented for `ParamEnvAnd<Self>`, since we always need to bring
59/// along a parameter environment as well. For query type-ops, we will
60/// first canonicalize the key and then invoke the query on the tcx,
61/// which produces the resulting query region constraints.
62///
f9f354fc 63/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
9ffffee4
FG
64pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 'tcx {
65 type QueryResponse: TypeFoldable<TyCtxt<'tcx>>;
8faf50e0
XL
66
67 /// Give query the option for a simple fast path that never
68 /// actually hits the tcx cache lookup etc. Return `Some(r)` with
69 /// a final result or `None` to do the full path.
70 fn try_fast_path(
dc9dc135 71 tcx: TyCtxt<'tcx>,
8faf50e0 72 key: &ParamEnvAnd<'tcx, Self>,
0bf4aa26 73 ) -> Option<Self::QueryResponse>;
8faf50e0
XL
74
75 /// Performs the actual query with the canonicalized key -- the
76 /// real work happens here. This method is not given an `infcx`
77 /// because it shouldn't need one -- and if it had access to one,
78 /// it might do things like invoke `sub_regions`, which would be
79 /// bad, because it would create subregion relationships that are
80 /// not captured in the return value.
81 fn perform_query(
dc9dc135 82 tcx: TyCtxt<'tcx>,
9c376795 83 canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
49aad941
FG
84 ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution>;
85
86 /// In the new trait solver, we already do caching in the solver itself,
87 /// so there's no need to canonicalize and cache via the query system.
88 /// Additionally, even if we were to canonicalize, we'd still need to
89 /// make sure to feed it predefined opaque types and the defining anchor
90 /// and that would require duplicating all of the tcx queries. Instead,
91 /// just perform these ops locally.
92 fn perform_locally_in_new_solver(
93 ocx: &ObligationCtxt<'_, 'tcx>,
94 key: ParamEnvAnd<'tcx, Self>,
95 ) -> Result<Self::QueryResponse, NoSolution>;
8faf50e0 96
8faf50e0
XL
97 fn fully_perform_into(
98 query_key: ParamEnvAnd<'tcx, Self>,
2b03887a 99 infcx: &InferCtxt<'tcx>,
dc9dc135 100 output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
49aad941
FG
101 ) -> Result<
102 (
103 Self::QueryResponse,
104 Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
105 PredicateObligations<'tcx>,
106 Certainty,
107 ),
108 NoSolution,
109 > {
8faf50e0 110 if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
5099ac24 111 return Ok((result, None, vec![], Certainty::Proven));
8faf50e0
XL
112 }
113
114 // FIXME(#33684) -- We need to use
136023e0 115 // `canonicalize_query_keep_static` here because of things
8faf50e0
XL
116 // like the subtype query, which go awry around
117 // `'static` otherwise.
0bf4aa26 118 let mut canonical_var_values = OriginalQueryValues::default();
fc512014 119 let old_param_env = query_key.param_env;
136023e0
XL
120 let canonical_self =
121 infcx.canonicalize_query_keep_static(query_key, &mut canonical_var_values);
8faf50e0 122 let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
8faf50e0 123
8faf50e0 124 let InferOk { value, obligations } = infcx
0bf4aa26 125 .instantiate_nll_query_response_and_region_obligations(
8faf50e0 126 &ObligationCause::dummy(),
fc512014 127 old_param_env,
8faf50e0
XL
128 &canonical_var_values,
129 canonical_result,
130 output_query_region_constraints,
131 )?;
132
5099ac24 133 Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
8faf50e0
XL
134 }
135}
136
dc9dc135 137impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
8faf50e0 138where
dc9dc135 139 Q: QueryTypeOp<'tcx>,
8faf50e0 140{
0bf4aa26 141 type Output = Q::QueryResponse;
5e7ed085 142 type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
8faf50e0 143
49aad941
FG
144 fn fully_perform(
145 self,
146 infcx: &InferCtxt<'tcx>,
147 span: Span,
148 ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
149 if infcx.tcx.trait_solver_next() {
150 return Ok(scrape_region_constraints(
151 infcx,
152 |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self),
153 "query type op",
154 span,
155 )?
156 .0);
157 }
158
dc9dc135 159 let mut region_constraints = QueryRegionConstraints::default();
5e7ed085 160 let (output, error_info, mut obligations, _) =
49aad941
FG
161 Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
162 infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}"))
163 })?;
8faf50e0 164
5099ac24
FG
165 // Typically, instantiating NLL query results does not
166 // create obligations. However, in some cases there
167 // are unresolved type variables, and unify them *can*
168 // create obligations. In that case, we have to go
169 // fulfill them. We do this via a (recursive) query.
170 while !obligations.is_empty() {
171 trace!("{:#?}", obligations);
172 let mut progress = false;
173 for obligation in std::mem::take(&mut obligations) {
174 let obligation = infcx.resolve_vars_if_possible(obligation);
175 match ProvePredicate::fully_perform_into(
176 obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
177 infcx,
178 &mut region_constraints,
179 ) {
180 Ok(((), _, new, certainty)) => {
181 obligations.extend(new);
182 progress = true;
183 if let Certainty::Ambiguous = certainty {
184 obligations.push(obligation);
185 }
186 }
187 Err(_) => obligations.push(obligation),
188 }
189 }
190 if !progress {
49aad941
FG
191 return Err(infcx.tcx.sess.delay_span_bug(
192 span,
193 format!("ambiguity processing {obligations:?} from {self:?}"),
194 ));
5099ac24
FG
195 }
196 }
197
064997fb
FG
198 Ok(TypeOpOutput {
199 output,
200 constraints: if region_constraints.is_empty() {
201 None
202 } else {
203 Some(infcx.tcx.arena.alloc(region_constraints))
204 },
205 error_info,
206 })
8faf50e0
XL
207 }
208}