Skip to content

Commit 207b4b8

Browse files
Record impl args in the InsepctCandiate rather than rematching during select
1 parent fc47cf3 commit 207b4b8

File tree

7 files changed

+99
-65
lines changed

7 files changed

+99
-65
lines changed

compiler/rustc_middle/src/traits/solve/inspect.rs

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ pub enum ProbeStep<'tcx> {
123123
/// used whenever there are multiple candidates to prove the
124124
/// current goalby .
125125
NestedProbe(Probe<'tcx>),
126+
/// A trait goal was satisfied by an impl candidate.
127+
RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
126128
/// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with
127129
/// `Certainty` was made. This is the certainty passed in, so it's not unified
128130
/// with the certainty of the `try_evaluate_added_goals` that is done within;

compiler/rustc_middle/src/traits/solve/inspect/format.rs

+3
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
136136
ProbeStep::MakeCanonicalResponse { shallow_certainty } => {
137137
writeln!(this.f, "EVALUATE GOALS AND MAKE RESPONSE: {shallow_certainty:?}")?
138138
}
139+
ProbeStep::RecordImplArgs { impl_args } => {
140+
writeln!(this.f, "RECORDED IMPL ARGS: {impl_args:?}")?
141+
}
139142
}
140143
}
141144
Ok(())

compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
587587

588588
Ok(unchanged_certainty)
589589
}
590+
591+
/// Record impl args in the proof tree for later access by `InspectCandidate`.
592+
pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) {
593+
self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args)
594+
}
590595
}
591596

592597
impl<'tcx> EvalCtxt<'_, 'tcx> {

compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs

+22-59
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use std::ops::ControlFlow;
22

3-
use rustc_hir::def_id::DefId;
4-
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
3+
use rustc_infer::infer::InferCtxt;
54
use rustc_infer::traits::solve::inspect::ProbeKind;
65
use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal};
76
use rustc_infer::traits::{
87
BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause,
9-
PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult,
8+
PolyTraitObligation, Selection, SelectionError, SelectionResult,
109
};
1110
use rustc_macros::extension;
1211
use rustc_span::Span;
@@ -133,32 +132,33 @@ fn to_selection<'tcx>(
133132
return None;
134133
}
135134

136-
let make_nested = || {
137-
cand.instantiate_nested_goals(span)
138-
.into_iter()
139-
.map(|nested| {
140-
Obligation::new(
141-
nested.infcx().tcx,
142-
ObligationCause::dummy_with_span(span),
143-
nested.goal().param_env,
144-
nested.goal().predicate,
145-
)
146-
})
147-
.collect()
148-
};
135+
let (nested, impl_args) = cand.instantiate_nested_goals_and_opt_impl_args(span);
136+
let nested = nested
137+
.into_iter()
138+
.map(|nested| {
139+
Obligation::new(
140+
nested.infcx().tcx,
141+
ObligationCause::dummy_with_span(span),
142+
nested.goal().param_env,
143+
nested.goal().predicate,
144+
)
145+
})
146+
.collect();
149147

150148
Some(match cand.kind() {
151149
ProbeKind::TraitCandidate { source, result: _ } => match source {
152150
CandidateSource::Impl(impl_def_id) => {
153151
// FIXME: Remove this in favor of storing this in the tree
154152
// For impl candidates, we do the rematch manually to compute the args.
155-
ImplSource::UserDefined(rematch_impl(cand.goal(), impl_def_id, span))
156-
}
157-
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, make_nested()),
158-
CandidateSource::ParamEnv(_) => ImplSource::Param(make_nested()),
159-
CandidateSource::AliasBound => {
160-
ImplSource::Builtin(BuiltinImplSource::Misc, make_nested())
153+
ImplSource::UserDefined(ImplSourceUserDefinedData {
154+
impl_def_id,
155+
args: impl_args.expect("expected recorded impl args for impl candidate"),
156+
nested,
157+
})
161158
}
159+
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
160+
CandidateSource::ParamEnv(_) => ImplSource::Param(nested),
161+
CandidateSource::AliasBound => ImplSource::Builtin(BuiltinImplSource::Misc, nested),
162162
CandidateSource::CoherenceUnknowable => {
163163
span_bug!(span, "didn't expect to select an unknowable candidate")
164164
}
@@ -173,40 +173,3 @@ fn to_selection<'tcx>(
173173
}
174174
})
175175
}
176-
177-
fn rematch_impl<'tcx>(
178-
goal: &inspect::InspectGoal<'_, 'tcx>,
179-
impl_def_id: DefId,
180-
span: Span,
181-
) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
182-
let infcx = goal.infcx();
183-
let goal_trait_ref = infcx
184-
.enter_forall_and_leak_universe(goal.goal().predicate.to_opt_poly_trait_pred().unwrap())
185-
.trait_ref;
186-
187-
let args = infcx.fresh_args_for_item(span, impl_def_id);
188-
let impl_trait_ref =
189-
infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args);
190-
191-
let InferOk { value: (), obligations: mut nested } = infcx
192-
.at(&ObligationCause::dummy_with_span(span), goal.goal().param_env)
193-
.eq(DefineOpaqueTypes::Yes, goal_trait_ref, impl_trait_ref)
194-
.expect("rematching impl failed");
195-
196-
// FIXME(-Znext-solver=coinductive): We need to add supertraits here eventually.
197-
198-
nested.extend(
199-
infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map(
200-
|(clause, _)| {
201-
Obligation::new(
202-
infcx.tcx,
203-
ObligationCause::dummy_with_span(span),
204-
goal.goal().param_env,
205-
clause,
206-
)
207-
},
208-
),
209-
);
210-
211-
ImplSourceUserDefinedData { impl_def_id, nested, args }
212-
}

compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

+37-5
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ pub struct InspectCandidate<'a, 'tcx> {
9393
kind: inspect::ProbeKind<'tcx>,
9494
nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>,
9595
final_state: inspect::CanonicalState<'tcx, ()>,
96+
impl_args: Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>>,
9697
result: QueryResult<'tcx>,
9798
shallow_certainty: Certainty,
9899
}
@@ -135,7 +136,20 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
135136

136137
/// Instantiate the nested goals for the candidate without rolling back their
137138
/// inference constraints. This function modifies the state of the `infcx`.
139+
///
140+
/// See [`Self::instantiate_nested_goals_and_opt_impl_args`] if you need the impl args too.
138141
pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> {
142+
self.instantiate_nested_goals_and_opt_impl_args(span).0
143+
}
144+
145+
/// Instantiate the nested goals for the candidate without rolling back their
146+
/// inference constraints, and optionally the args of an impl if this candidate
147+
/// came from a `CandidateSource::Impl`. This function modifies the state of the
148+
/// `infcx`.
149+
pub fn instantiate_nested_goals_and_opt_impl_args(
150+
&self,
151+
span: Span,
152+
) -> (Vec<InspectGoal<'a, 'tcx>>, Option<ty::GenericArgsRef<'tcx>>) {
139153
let infcx = self.goal.infcx;
140154
let param_env = self.goal.goal.param_env;
141155
let mut orig_values = self.goal.orig_values.to_vec();
@@ -164,14 +178,25 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
164178
self.final_state,
165179
);
166180

181+
let impl_args = self.impl_args.map(|impl_args| {
182+
canonical::instantiate_canonical_state(
183+
infcx,
184+
span,
185+
param_env,
186+
&mut orig_values,
187+
impl_args,
188+
)
189+
.fold_with(&mut EagerResolver::new(infcx))
190+
});
191+
167192
if let Some(term_hack) = self.goal.normalizes_to_term_hack {
168193
// FIXME: We ignore the expected term of `NormalizesTo` goals
169194
// when computing the result of its candidates. This is
170195
// scuffed.
171196
let _ = term_hack.constrain(infcx, span, param_env);
172197
}
173198

174-
instantiated_goals
199+
let goals = instantiated_goals
175200
.into_iter()
176201
.map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
177202
Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
@@ -208,7 +233,9 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
208233
source,
209234
),
210235
})
211-
.collect()
236+
.collect();
237+
238+
(goals, impl_args)
212239
}
213240

214241
/// Visit all nested goals of this candidate, rolling back
@@ -245,9 +272,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
245272
probe: &inspect::Probe<'tcx>,
246273
) {
247274
let mut shallow_certainty = None;
275+
let mut impl_args = None;
248276
for step in &probe.steps {
249-
match step {
250-
&inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
277+
match *step {
278+
inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
251279
inspect::ProbeStep::NestedProbe(ref probe) => {
252280
// Nested probes have to prove goals added in their parent
253281
// but do not leak them, so we truncate the added goals
@@ -257,7 +285,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
257285
nested_goals.truncate(num_goals);
258286
}
259287
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
260-
assert_eq!(shallow_certainty.replace(*c), None);
288+
assert_eq!(shallow_certainty.replace(c), None);
289+
}
290+
inspect::ProbeStep::RecordImplArgs { impl_args: i } => {
291+
assert_eq!(impl_args.replace(i), None);
261292
}
262293
inspect::ProbeStep::EvaluateGoals(_) => (),
263294
}
@@ -284,6 +315,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
284315
final_state: probe.final_state,
285316
result,
286317
shallow_certainty,
318+
impl_args,
287319
});
288320
}
289321
}

compiler/rustc_trait_selection/src/solve/inspect/build.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ enum WipProbeStep<'tcx> {
242242
EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
243243
NestedProbe(WipProbe<'tcx>),
244244
MakeCanonicalResponse { shallow_certainty: Certainty },
245+
RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
245246
}
246247

247248
impl<'tcx> WipProbeStep<'tcx> {
@@ -250,6 +251,9 @@ impl<'tcx> WipProbeStep<'tcx> {
250251
WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
251252
WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
252253
WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
254+
WipProbeStep::RecordImplArgs { impl_args } => {
255+
inspect::ProbeStep::RecordImplArgs { impl_args }
256+
}
253257
WipProbeStep::MakeCanonicalResponse { shallow_certainty } => {
254258
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty }
255259
}
@@ -534,6 +538,30 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
534538
}
535539
}
536540

541+
pub(crate) fn record_impl_args(
542+
&mut self,
543+
infcx: &InferCtxt<'tcx>,
544+
max_input_universe: ty::UniverseIndex,
545+
impl_args: ty::GenericArgsRef<'tcx>,
546+
) {
547+
match self.as_mut() {
548+
Some(DebugSolver::GoalEvaluationStep(state)) => {
549+
let impl_args = canonical::make_canonical_state(
550+
infcx,
551+
&state.var_values,
552+
max_input_universe,
553+
impl_args,
554+
);
555+
state
556+
.current_evaluation_scope()
557+
.steps
558+
.push(WipProbeStep::RecordImplArgs { impl_args });
559+
}
560+
None => {}
561+
_ => bug!(),
562+
}
563+
}
564+
537565
pub fn make_canonical_response(&mut self, shallow_certainty: Certainty) {
538566
match self.as_mut() {
539567
Some(DebugSolver::GoalEvaluationStep(state)) => {
@@ -543,7 +571,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
543571
.push(WipProbeStep::MakeCanonicalResponse { shallow_certainty });
544572
}
545573
None => {}
546-
_ => {}
574+
_ => bug!(),
547575
}
548576
}
549577

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
7575

7676
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
7777
let impl_args = ecx.fresh_args_for_item(impl_def_id);
78+
ecx.record_impl_args(impl_args);
7879
let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args);
7980

8081
ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;

0 commit comments

Comments
 (0)