|
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