|
11 | 11 |
|
12 | 12 | use std::iter;
|
13 | 13 |
|
| 14 | +use canonicalizer::Canonicalizer; |
14 | 15 | use rustc_index::IndexVec;
|
15 |
| -use rustc_type_ir::data_structures::HashSet; |
16 | 16 | use rustc_type_ir::inherent::*;
|
17 | 17 | use rustc_type_ir::relate::solver_relating::RelateExt;
|
18 | 18 | use rustc_type_ir::{
|
19 | 19 | self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
|
20 | 20 | TypeFoldable,
|
21 | 21 | };
|
22 |
| -use tracing::{debug, instrument, trace}; |
| 22 | +use tracing::instrument; |
23 | 23 |
|
24 |
| -use crate::canonicalizer::Canonicalizer; |
25 | 24 | use crate::delegate::SolverDelegate;
|
26 | 25 | use crate::resolve::eager_resolve_vars;
|
27 |
| -use crate::solve::eval_ctxt::CurrentGoalKind; |
28 | 26 | use crate::solve::{
|
29 | 27 | CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal,
|
30 |
| - MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput, |
31 |
| - QueryResult, Response, inspect, response_no_constraints_raw, |
| 28 | + NestedNormalizationGoals, PredefinedOpaquesData, QueryInput, Response, inspect, |
32 | 29 | };
|
33 | 30 |
|
| 31 | +pub mod canonicalizer; |
| 32 | + |
34 | 33 | trait ResponseT<I: Interner> {
|
35 | 34 | fn var_values(&self) -> CanonicalVarValues<I>;
|
36 | 35 | }
|
@@ -77,193 +76,6 @@ where
|
77 | 76 | (orig_values, query_input)
|
78 | 77 | }
|
79 | 78 |
|
80 |
| - /// To return the constraints of a canonical query to the caller, we canonicalize: |
81 |
| - /// |
82 |
| - /// - `var_values`: a map from bound variables in the canonical goal to |
83 |
| - /// the values inferred while solving the instantiated goal. |
84 |
| - /// - `external_constraints`: additional constraints which aren't expressible |
85 |
| - /// using simple unification of inference variables. |
86 |
| - /// |
87 |
| - /// This takes the `shallow_certainty` which represents whether we're confident |
88 |
| - /// that the final result of the current goal only depends on the nested goals. |
89 |
| - /// |
90 |
| - /// In case this is `Certainty::Maybe`, there may still be additional nested goals |
91 |
| - /// or inference constraints required for this candidate to be hold. The candidate |
92 |
| - /// always requires all already added constraints and nested goals. |
93 |
| - #[instrument(level = "trace", skip(self), ret)] |
94 |
| - pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( |
95 |
| - &mut self, |
96 |
| - shallow_certainty: Certainty, |
97 |
| - ) -> QueryResult<I> { |
98 |
| - self.inspect.make_canonical_response(shallow_certainty); |
99 |
| - |
100 |
| - let goals_certainty = self.try_evaluate_added_goals()?; |
101 |
| - assert_eq!( |
102 |
| - self.tainted, |
103 |
| - Ok(()), |
104 |
| - "EvalCtxt is tainted -- nested goals may have been dropped in a \ |
105 |
| - previous call to `try_evaluate_added_goals!`" |
106 |
| - ); |
107 |
| - |
108 |
| - // We only check for leaks from universes which were entered inside |
109 |
| - // of the query. |
110 |
| - self.delegate.leak_check(self.max_input_universe).map_err(|NoSolution| { |
111 |
| - trace!("failed the leak check"); |
112 |
| - NoSolution |
113 |
| - })?; |
114 |
| - |
115 |
| - let (certainty, normalization_nested_goals) = |
116 |
| - match (self.current_goal_kind, shallow_certainty) { |
117 |
| - // When normalizing, we've replaced the expected term with an unconstrained |
118 |
| - // inference variable. This means that we dropped information which could |
119 |
| - // have been important. We handle this by instead returning the nested goals |
120 |
| - // to the caller, where they are then handled. We only do so if we do not |
121 |
| - // need to recompute the `NormalizesTo` goal afterwards to avoid repeatedly |
122 |
| - // uplifting its nested goals. This is the case if the `shallow_certainty` is |
123 |
| - // `Certainty::Yes`. |
124 |
| - (CurrentGoalKind::NormalizesTo, Certainty::Yes) => { |
125 |
| - let goals = std::mem::take(&mut self.nested_goals); |
126 |
| - // As we return all ambiguous nested goals, we can ignore the certainty |
127 |
| - // returned by `self.try_evaluate_added_goals()`. |
128 |
| - if goals.is_empty() { |
129 |
| - assert!(matches!(goals_certainty, Certainty::Yes)); |
130 |
| - } |
131 |
| - ( |
132 |
| - Certainty::Yes, |
133 |
| - NestedNormalizationGoals( |
134 |
| - goals.into_iter().map(|(s, g, _)| (s, g)).collect(), |
135 |
| - ), |
136 |
| - ) |
137 |
| - } |
138 |
| - _ => { |
139 |
| - let certainty = shallow_certainty.and(goals_certainty); |
140 |
| - (certainty, NestedNormalizationGoals::empty()) |
141 |
| - } |
142 |
| - }; |
143 |
| - |
144 |
| - if let Certainty::Maybe(cause @ MaybeCause::Overflow { keep_constraints: false, .. }) = |
145 |
| - certainty |
146 |
| - { |
147 |
| - // If we have overflow, it's probable that we're substituting a type |
148 |
| - // into itself infinitely and any partial substitutions in the query |
149 |
| - // response are probably not useful anyways, so just return an empty |
150 |
| - // query response. |
151 |
| - // |
152 |
| - // This may prevent us from potentially useful inference, e.g. |
153 |
| - // 2 candidates, one ambiguous and one overflow, which both |
154 |
| - // have the same inference constraints. |
155 |
| - // |
156 |
| - // Changing this to retain some constraints in the future |
157 |
| - // won't be a breaking change, so this is good enough for now. |
158 |
| - return Ok(self.make_ambiguous_response_no_constraints(cause)); |
159 |
| - } |
160 |
| - |
161 |
| - let external_constraints = |
162 |
| - self.compute_external_query_constraints(certainty, normalization_nested_goals); |
163 |
| - let (var_values, mut external_constraints) = |
164 |
| - eager_resolve_vars(self.delegate, (self.var_values, external_constraints)); |
165 |
| - |
166 |
| - // Remove any trivial or duplicated region constraints once we've resolved regions |
167 |
| - let mut unique = HashSet::default(); |
168 |
| - external_constraints.region_constraints.retain(|outlives| { |
169 |
| - outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives) |
170 |
| - }); |
171 |
| - |
172 |
| - let canonical = Canonicalizer::canonicalize_response( |
173 |
| - self.delegate, |
174 |
| - self.max_input_universe, |
175 |
| - &mut Default::default(), |
176 |
| - Response { |
177 |
| - var_values, |
178 |
| - certainty, |
179 |
| - external_constraints: self.cx().mk_external_constraints(external_constraints), |
180 |
| - }, |
181 |
| - ); |
182 |
| - |
183 |
| - // HACK: We bail with overflow if the response would have too many non-region |
184 |
| - // inference variables. This tends to only happen if we encounter a lot of |
185 |
| - // ambiguous alias types which get replaced with fresh inference variables |
186 |
| - // during generalization. This prevents hangs caused by an exponential blowup, |
187 |
| - // see tests/ui/traits/next-solver/coherence-alias-hang.rs. |
188 |
| - match self.current_goal_kind { |
189 |
| - // We don't do so for `NormalizesTo` goals as we erased the expected term and |
190 |
| - // bailing with overflow here would prevent us from detecting a type-mismatch, |
191 |
| - // causing a coherence error in diesel, see #131969. We still bail with overflow |
192 |
| - // when later returning from the parent AliasRelate goal. |
193 |
| - CurrentGoalKind::NormalizesTo => {} |
194 |
| - CurrentGoalKind::Misc | CurrentGoalKind::CoinductiveTrait => { |
195 |
| - let num_non_region_vars = canonical |
196 |
| - .variables |
197 |
| - .iter() |
198 |
| - .filter(|c| !c.is_region() && c.is_existential()) |
199 |
| - .count(); |
200 |
| - if num_non_region_vars > self.cx().recursion_limit() { |
201 |
| - debug!(?num_non_region_vars, "too many inference variables -> overflow"); |
202 |
| - return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow { |
203 |
| - suggest_increasing_limit: true, |
204 |
| - keep_constraints: false, |
205 |
| - })); |
206 |
| - } |
207 |
| - } |
208 |
| - } |
209 |
| - |
210 |
| - Ok(canonical) |
211 |
| - } |
212 |
| - |
213 |
| - /// Constructs a totally unconstrained, ambiguous response to a goal. |
214 |
| - /// |
215 |
| - /// Take care when using this, since often it's useful to respond with |
216 |
| - /// ambiguity but return constrained variables to guide inference. |
217 |
| - pub(in crate::solve) fn make_ambiguous_response_no_constraints( |
218 |
| - &self, |
219 |
| - maybe_cause: MaybeCause, |
220 |
| - ) -> CanonicalResponse<I> { |
221 |
| - response_no_constraints_raw( |
222 |
| - self.cx(), |
223 |
| - self.max_input_universe, |
224 |
| - self.variables, |
225 |
| - Certainty::Maybe(maybe_cause), |
226 |
| - ) |
227 |
| - } |
228 |
| - |
229 |
| - /// Computes the region constraints and *new* opaque types registered when |
230 |
| - /// proving a goal. |
231 |
| - /// |
232 |
| - /// If an opaque was already constrained before proving this goal, then the |
233 |
| - /// external constraints do not need to record that opaque, since if it is |
234 |
| - /// further constrained by inference, that will be passed back in the var |
235 |
| - /// values. |
236 |
| - #[instrument(level = "trace", skip(self), ret)] |
237 |
| - fn compute_external_query_constraints( |
238 |
| - &self, |
239 |
| - certainty: Certainty, |
240 |
| - normalization_nested_goals: NestedNormalizationGoals<I>, |
241 |
| - ) -> ExternalConstraintsData<I> { |
242 |
| - // We only return region constraints once the certainty is `Yes`. This |
243 |
| - // is necessary as we may drop nested goals on ambiguity, which may result |
244 |
| - // in unconstrained inference variables in the region constraints. It also |
245 |
| - // prevents us from emitting duplicate region constraints, avoiding some |
246 |
| - // unnecessary work. This slightly weakens the leak check in case it uses |
247 |
| - // region constraints from an ambiguous nested goal. This is tested in both |
248 |
| - // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and |
249 |
| - // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. |
250 |
| - let region_constraints = if certainty == Certainty::Yes { |
251 |
| - self.delegate.make_deduplicated_outlives_constraints() |
252 |
| - } else { |
253 |
| - Default::default() |
254 |
| - }; |
255 |
| - |
256 |
| - // We only return *newly defined* opaque types from canonical queries. |
257 |
| - // |
258 |
| - // Constraints for any existing opaque types are already tracked by changes |
259 |
| - // to the `var_values`. |
260 |
| - let opaque_types = self |
261 |
| - .delegate |
262 |
| - .clone_opaque_types_added_since(self.initial_opaque_types_storage_num_entries); |
263 |
| - |
264 |
| - ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } |
265 |
| - } |
266 |
| - |
267 | 79 | /// After calling a canonical query, we apply the constraints returned
|
268 | 80 | /// by the query using this function.
|
269 | 81 | ///
|
@@ -462,7 +274,7 @@ where
|
462 | 274 | /// evaluating a goal. The `var_values` not only include the bound variables
|
463 | 275 | /// of the query input, but also contain all unconstrained inference vars
|
464 | 276 | /// created while evaluating this goal.
|
465 |
| -pub(in crate::solve) fn make_canonical_state<D, T, I>( |
| 277 | +pub fn make_canonical_state<D, T, I>( |
466 | 278 | delegate: &D,
|
467 | 279 | var_values: &[I::GenericArg],
|
468 | 280 | max_input_universe: ty::UniverseIndex,
|
@@ -508,3 +320,22 @@ where
|
508 | 320 | EvalCtxt::unify_query_var_values(delegate, param_env, orig_values, var_values, span);
|
509 | 321 | data
|
510 | 322 | }
|
| 323 | + |
| 324 | +pub fn response_no_constraints_raw<I: Interner>( |
| 325 | + cx: I, |
| 326 | + max_universe: ty::UniverseIndex, |
| 327 | + variables: I::CanonicalVarKinds, |
| 328 | + certainty: Certainty, |
| 329 | +) -> CanonicalResponse<I> { |
| 330 | + ty::Canonical { |
| 331 | + max_universe, |
| 332 | + variables, |
| 333 | + value: Response { |
| 334 | + var_values: ty::CanonicalVarValues::make_identity(cx, variables), |
| 335 | + // FIXME: maybe we should store the "no response" version in cx, like |
| 336 | + // we do for cx.types and stuff. |
| 337 | + external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()), |
| 338 | + certainty, |
| 339 | + }, |
| 340 | + } |
| 341 | +} |
0 commit comments