Skip to content

Commit a6816aa

Browse files
committed
move mod canonical out of eval_ctxt
1 parent 0c0c58b commit a6816aa

File tree

9 files changed

+229
-231
lines changed

9 files changed

+229
-231
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 & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +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;
18-
use rustc_type_ir::solve::OpaqueTypesJank;
1918
use rustc_type_ir::{
2019
self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
2120
TypeFoldable,
2221
};
23-
use tracing::{debug, instrument, trace};
22+
use tracing::instrument;
2423

25-
use crate::canonicalizer::Canonicalizer;
2624
use crate::delegate::SolverDelegate;
2725
use crate::resolve::eager_resolve_vars;
28-
use crate::solve::eval_ctxt::CurrentGoalKind;
2926
use crate::solve::{
3027
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,
3329
};
3430

31+
pub mod canonicalizer;
32+
3533
trait ResponseT<I: Interner> {
3634
fn var_values(&self) -> CanonicalVarValues<I>;
3735
}
@@ -78,199 +76,6 @@ where
7876
(orig_values, query_input)
7977
}
8078

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-
27479
/// After calling a canonical query, we apply the constraints returned
27580
/// by the query using this function.
27681
///
@@ -469,7 +274,7 @@ where
469274
/// evaluating a goal. The `var_values` not only include the bound variables
470275
/// of the query input, but also contain all unconstrained inference vars
471276
/// 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>(
473278
delegate: &D,
474279
var_values: &[I::GenericArg],
475280
max_input_universe: ty::UniverseIndex,
@@ -515,3 +320,22 @@ where
515320
EvalCtxt::unify_query_var_values(delegate, param_env, orig_values, var_values, span);
516321
data
517322
}
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)