Skip to content

Commit aa8d846

Browse files
committed
move mod canonical out of eval_ctxt
1 parent 4793ef5 commit aa8d846

File tree

9 files changed

+223
-224
lines changed

9 files changed

+223
-224
lines changed
File renamed without changes.

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs renamed to compiler/rustc_next_trait_solver/src/canonical/mod.rs

Lines changed: 25 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,25 @@
1111
1212
use std::iter;
1313

14+
use canonicalizer::Canonicalizer;
1415
use rustc_index::IndexVec;
15-
use rustc_type_ir::data_structures::HashSet;
1616
use rustc_type_ir::inherent::*;
1717
use rustc_type_ir::relate::solver_relating::RelateExt;
1818
use rustc_type_ir::{
1919
self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
2020
TypeFoldable,
2121
};
22-
use tracing::{debug, instrument, trace};
22+
use tracing::instrument;
2323

24-
use crate::canonicalizer::Canonicalizer;
2524
use crate::delegate::SolverDelegate;
2625
use crate::resolve::eager_resolve_vars;
27-
use crate::solve::eval_ctxt::CurrentGoalKind;
2826
use crate::solve::{
2927
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,
3229
};
3330

31+
pub mod canonicalizer;
32+
3433
trait ResponseT<I: Interner> {
3534
fn var_values(&self) -> CanonicalVarValues<I>;
3635
}
@@ -77,193 +76,6 @@ where
7776
(orig_values, query_input)
7877
}
7978

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-
26779
/// After calling a canonical query, we apply the constraints returned
26880
/// by the query using this function.
26981
///
@@ -462,7 +274,7 @@ where
462274
/// evaluating a goal. The `var_values` not only include the bound variables
463275
/// of the query input, but also contain all unconstrained inference vars
464276
/// 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>(
466278
delegate: &D,
467279
var_values: &[I::GenericArg],
468280
max_input_universe: ty::UniverseIndex,
@@ -508,3 +320,22 @@ where
508320
EvalCtxt::unify_query_var_values(delegate, param_env, orig_values, var_values, span);
509321
data
510322
}
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+
}

compiler/rustc_next_trait_solver/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#![allow(rustc::usage_of_type_ir_traits)]
1111
// tidy-alphabetical-end
1212

13-
pub mod canonicalizer;
13+
pub mod canonical;
1414
pub mod coherence;
1515
pub mod delegate;
1616
pub mod placeholder;

0 commit comments

Comments
 (0)