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