Rollup merge of #140641 - lcnr:opaque-type-storage-entries, r=compiler-errors

detect additional uses of opaques after writeback

Based on #140607. It's a lot harder to encounter in practice than I though 😅 😁 I've still added it with the expectation that somebody will encounter it at some point.

Also modifies the `EvalCtxt` to use the same impl to detect newly added opaque types.

r? ``@compiler-errors``
This commit is contained in:
Matthias Krüger
2025-05-08 08:14:18 +02:00
committed by GitHub
14 changed files with 204 additions and 139 deletions

View File

@@ -250,13 +250,7 @@ where
// to the `var_values`.
let opaque_types = self
.delegate
.clone_opaque_types_lookup_table()
.into_iter()
.filter(|(a, _)| {
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
})
.chain(self.delegate.clone_duplicate_opaque_types())
.collect();
.clone_opaque_types_added_since(self.initial_opaque_types_storage_num_entries);
ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
}

View File

@@ -23,8 +23,7 @@ use crate::solve::inspect::{self, ProofTreeBuilder};
use crate::solve::search_graph::SearchGraph;
use crate::solve::{
CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource,
HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput,
QueryResult,
HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, QueryResult,
};
pub(super) mod canonical;
@@ -99,8 +98,6 @@ where
current_goal_kind: CurrentGoalKind,
pub(super) var_values: CanonicalVarValues<I>,
predefined_opaques_in_body: I::PredefinedOpaques,
/// The highest universe index nameable by the caller.
///
/// When we enter a new binder inside of the query we create new universes
@@ -111,6 +108,10 @@ where
/// if we have a coinductive cycle and because that's the only way we can return
/// new placeholders to the caller.
pub(super) max_input_universe: ty::UniverseIndex,
/// The opaque types from the canonical input. We only need to return opaque types
/// which have been added to the storage while evaluating this goal.
pub(super) initial_opaque_types_storage_num_entries:
<D::Infcx as InferCtxtLike>::OpaqueTypeStorageEntries,
pub(super) search_graph: &'a mut SearchGraph<D>,
@@ -305,10 +306,8 @@ where
// Only relevant when canonicalizing the response,
// which we don't do within this evaluation context.
predefined_opaques_in_body: delegate
.cx()
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
max_input_universe: ty::UniverseIndex::ROOT,
initial_opaque_types_storage_num_entries: Default::default(),
variables: Default::default(),
var_values: CanonicalVarValues::dummy(),
current_goal_kind: CurrentGoalKind::Misc,
@@ -342,25 +341,10 @@ where
canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
) -> R {
let (ref delegate, input, var_values) =
SolverDelegate::build_with_canonical(cx, &canonical_input);
let mut ecx = EvalCtxt {
delegate,
variables: canonical_input.canonical.variables,
var_values,
current_goal_kind: CurrentGoalKind::from_query_input(cx, input),
predefined_opaques_in_body: input.predefined_opaques_in_body,
max_input_universe: canonical_input.canonical.max_universe,
search_graph,
nested_goals: Default::default(),
origin_span: I::Span::dummy(),
tainted: Ok(()),
inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
};
let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input);
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
let prev = ecx.delegate.register_hidden_type_in_storage(key, ty, ecx.origin_span);
let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy());
// It may be possible that two entries in the opaque type storage end up
// with the same key after resolving contained inference variables.
//
@@ -373,13 +357,24 @@ where
// the canonical input. This is more annoying to implement and may cause a
// perf regression, so we do it inside of the query for now.
if let Some(prev) = prev {
debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_type_storage`");
debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
}
}
if !ecx.nested_goals.is_empty() {
panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals);
}
let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries();
let mut ecx = EvalCtxt {
delegate,
variables: canonical_input.canonical.variables,
var_values,
current_goal_kind: CurrentGoalKind::from_query_input(cx, input),
max_input_universe: canonical_input.canonical.max_universe,
initial_opaque_types_storage_num_entries,
search_graph,
nested_goals: Default::default(),
origin_span: I::Span::dummy(),
tainted: Ok(()),
inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
};
let result = f(&mut ecx, input.goal);
ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe);

View File

@@ -26,32 +26,33 @@ where
I: Interner,
{
pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T {
let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
let ProbeCtxt { ecx: outer, probe_kind, _result } = self;
let delegate = outer_ecx.delegate;
let max_input_universe = outer_ecx.max_input_universe;
let mut nested_ecx = EvalCtxt {
let delegate = outer.delegate;
let max_input_universe = outer.max_input_universe;
let mut nested = EvalCtxt {
delegate,
variables: outer_ecx.variables,
var_values: outer_ecx.var_values,
current_goal_kind: outer_ecx.current_goal_kind,
predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body,
variables: outer.variables,
var_values: outer.var_values,
current_goal_kind: outer.current_goal_kind,
max_input_universe,
search_graph: outer_ecx.search_graph,
nested_goals: outer_ecx.nested_goals.clone(),
origin_span: outer_ecx.origin_span,
tainted: outer_ecx.tainted,
inspect: outer_ecx.inspect.take_and_enter_probe(),
initial_opaque_types_storage_num_entries: outer
.initial_opaque_types_storage_num_entries,
search_graph: outer.search_graph,
nested_goals: outer.nested_goals.clone(),
origin_span: outer.origin_span,
tainted: outer.tainted,
inspect: outer.inspect.take_and_enter_probe(),
};
let r = nested_ecx.delegate.probe(|| {
let r = f(&mut nested_ecx);
nested_ecx.inspect.probe_final_state(delegate, max_input_universe);
let r = nested.delegate.probe(|| {
let r = f(&mut nested);
nested.inspect.probe_final_state(delegate, max_input_universe);
r
});
if !nested_ecx.inspect.is_noop() {
if !nested.inspect.is_noop() {
let probe_kind = probe_kind(&r);
nested_ecx.inspect.probe_kind(probe_kind);
outer_ecx.inspect = nested_ecx.inspect.finish_probe();
nested.inspect.probe_kind(probe_kind);
outer.inspect = nested.inspect.finish_probe();
}
r
}