Skip to content

Commit 7c58fc4

Browse files
Record impl args in the proof tree
1 parent 7c4ac06 commit 7c58fc4

File tree

12 files changed

+131
-98
lines changed

12 files changed

+131
-98
lines changed

compiler/rustc_middle/src/traits/solve.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@ pub enum GoalSource {
279279

280280
/// Possible ways the given goal can be proven.
281281
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
282-
pub enum CandidateSource {
283-
/// A user written impl.
282+
pub enum CandidateSource<'tcx> {
283+
/// A user written impl. Optionally, impl args are recorded if proof trees are
284+
/// enabled, this came from a trait goal and the goal succeeded or was ambiguous.
284285
///
285286
/// ## Examples
286287
///
@@ -291,7 +292,7 @@ pub enum CandidateSource {
291292
/// let y = x.clone();
292293
/// }
293294
/// ```
294-
Impl(DefId),
295+
Impl(DefId, Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>>),
295296
/// A builtin impl generated by the compiler. When adding a new special
296297
/// trait, try to use actual impls whenever possible. Builtin impls should
297298
/// only be used in cases where the impl cannot be manually be written.

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub enum ProbeKind<'tcx> {
143143
/// Probe entered when normalizing the self ty during candidate assembly
144144
NormalizedSelfTyAssembly,
145145
/// A candidate for proving a trait or alias-relate goal.
146-
TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
146+
TraitCandidate { source: CandidateSource<'tcx>, result: QueryResult<'tcx> },
147147
/// Used in the probe that wraps normalizing the non-self type for the unsize
148148
/// trait, which is also structurally matched on.
149149
UnsizeAssembly,

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub(super) mod structural_traits;
2525
/// and the `result` when using the given `source`.
2626
#[derive(Debug, Clone)]
2727
pub(super) struct Candidate<'tcx> {
28-
pub(super) source: CandidateSource,
28+
pub(super) source: CandidateSource<'tcx>,
2929
pub(super) result: CanonicalResponse<'tcx>,
3030
}
3131

@@ -47,7 +47,7 @@ pub(super) trait GoalKind<'tcx>:
4747
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
4848
fn probe_and_match_goal_against_assumption(
4949
ecx: &mut EvalCtxt<'_, 'tcx>,
50-
source: CandidateSource,
50+
source: CandidateSource<'tcx>,
5151
goal: Goal<'tcx, Self>,
5252
assumption: ty::Clause<'tcx>,
5353
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
@@ -58,7 +58,7 @@ pub(super) trait GoalKind<'tcx>:
5858
/// goal by equating it with the assumption.
5959
fn probe_and_consider_implied_clause(
6060
ecx: &mut EvalCtxt<'_, 'tcx>,
61-
parent_source: CandidateSource,
61+
parent_source: CandidateSource<'tcx>,
6262
goal: Goal<'tcx, Self>,
6363
assumption: ty::Clause<'tcx>,
6464
requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
@@ -76,7 +76,7 @@ pub(super) trait GoalKind<'tcx>:
7676
/// since they're not implied by the well-formedness of the object type.
7777
fn probe_and_consider_object_bound_candidate(
7878
ecx: &mut EvalCtxt<'_, 'tcx>,
79-
source: CandidateSource,
79+
source: CandidateSource<'tcx>,
8080
goal: Goal<'tcx, Self>,
8181
assumption: ty::Clause<'tcx>,
8282
) -> Result<Candidate<'tcx>, NoSolution> {
@@ -813,7 +813,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
813813
// This feels dangerous.
814814
Certainty::Yes => {
815815
candidates.retain(|c| match c.source {
816-
CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_) => {
816+
CandidateSource::Impl(_, _) | CandidateSource::BuiltinImpl(_) => {
817817
debug!(?c, "discard impl candidate");
818818
false
819819
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -1090,4 +1090,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
10901090
ControlFlow::Continue(())
10911091
});
10921092
}
1093+
1094+
pub(crate) fn canonicalize_impl_args(
1095+
&self,
1096+
impl_args: ty::GenericArgsRef<'tcx>,
1097+
) -> Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>> {
1098+
self.inspect.canonicalize_impl_args(self.infcx, self.max_input_universe, impl_args)
1099+
}
10931100
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ where
5151

5252
pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> {
5353
cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>,
54-
source: CandidateSource,
54+
source: CandidateSource<'tcx>,
5555
}
5656

5757
impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F>
@@ -86,7 +86,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
8686

8787
pub(in crate::solve) fn probe_trait_candidate(
8888
&mut self,
89-
source: CandidateSource,
89+
source: CandidateSource<'tcx>,
9090
) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
9191
{
9292
TraitProbeCtxt {

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

+30-64
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;
@@ -112,12 +111,14 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
112111
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
113112
) => false,
114113
(
115-
CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound,
114+
CandidateSource::Impl(_, _)
115+
| CandidateSource::ParamEnv(_)
116+
| CandidateSource::AliasBound,
116117
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
117118
) => true,
118119

119120
// Prefer specializing candidates over specialized candidates.
120-
(CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
121+
(CandidateSource::Impl(victim_def_id, _), CandidateSource::Impl(other_def_id, _)) => {
121122
victim.goal().infcx().tcx.specializes((other_def_id, victim_def_id))
122123
}
123124

@@ -133,32 +134,34 @@ fn to_selection<'tcx>(
133134
return None;
134135
}
135136

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-
};
137+
let nested = cand
138+
.instantiate_nested_goals(span)
139+
.into_iter()
140+
.map(|nested| {
141+
Obligation::new(
142+
nested.infcx().tcx,
143+
ObligationCause::dummy_with_span(span),
144+
nested.goal().param_env,
145+
nested.goal().predicate,
146+
)
147+
})
148+
.collect();
149149

150150
Some(match cand.kind() {
151151
ProbeKind::TraitCandidate { source, result: _ } => match source {
152-
CandidateSource::Impl(impl_def_id) => {
153-
// FIXME: Remove this in favor of storing this in the tree
154-
// 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())
152+
CandidateSource::Impl(impl_def_id, impl_args) => {
153+
ImplSource::UserDefined(ImplSourceUserDefinedData {
154+
impl_def_id,
155+
args: cand.instantiate_impl_args(
156+
impl_args.expect("expected impl args to be recorded"),
157+
span,
158+
),
159+
nested,
160+
})
161161
}
162+
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
163+
CandidateSource::ParamEnv(_) => ImplSource::Param(nested),
164+
CandidateSource::AliasBound => ImplSource::Builtin(BuiltinImplSource::Misc, nested),
162165
CandidateSource::CoherenceUnknowable => {
163166
span_bug!(span, "didn't expect to select an unknowable candidate")
164167
}
@@ -173,40 +176,3 @@ fn to_selection<'tcx>(
173176
}
174177
})
175178
}
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/fulfill.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
324324
};
325325

326326
// Don't walk into impls that have `do_not_recommend`.
327-
if let ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } =
328-
candidate.kind()
327+
if let ProbeKind::TraitCandidate {
328+
source: CandidateSource::Impl(impl_def_id, _),
329+
result: _,
330+
} = candidate.kind()
329331
&& goal.infcx().tcx.has_attr(impl_def_id, sym::do_not_recommend)
330332
{
331333
return ControlFlow::Break(self.obligation.clone());
@@ -388,7 +390,7 @@ fn derive_cause<'tcx>(
388390
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
389391
) -> ObligationCause<'tcx> {
390392
match candidate_kind {
391-
ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } => {
393+
ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id, _), result: _ } => {
392394
if let Some((_, span)) =
393395
tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
394396
{

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

+25
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,31 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
216216
pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
217217
self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor))
218218
}
219+
220+
pub(crate) fn instantiate_impl_args(
221+
&self,
222+
impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>,
223+
span: Span,
224+
) -> ty::GenericArgsRef<'tcx> {
225+
let infcx = self.goal.infcx;
226+
let param_env = self.goal.goal.param_env;
227+
let mut orig_values = self.goal.orig_values.to_vec();
228+
let args = canonical::instantiate_canonical_state(
229+
infcx,
230+
span,
231+
param_env,
232+
&mut orig_values,
233+
impl_args,
234+
);
235+
let () = canonical::instantiate_canonical_state(
236+
infcx,
237+
span,
238+
param_env,
239+
&mut orig_values,
240+
self.final_state,
241+
);
242+
infcx.resolve_vars_if_possible(args)
243+
}
219244
}
220245

221246
impl<'a, 'tcx> InspectGoal<'a, 'tcx> {

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

+19
Original file line numberDiff line numberDiff line change
@@ -614,4 +614,23 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
614614
}
615615
}
616616
}
617+
618+
/// Optionally canonicalize impl args. This will return `None` if proof trees are disabled.
619+
pub(crate) fn canonicalize_impl_args(
620+
&self,
621+
infcx: &InferCtxt<'tcx>,
622+
max_input_universe: ty::UniverseIndex,
623+
impl_args: ty::GenericArgsRef<'tcx>,
624+
) -> Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>> {
625+
match self.state.as_deref() {
626+
None => None,
627+
Some(DebugSolver::GoalEvaluationStep(state)) => Some(canonical::make_canonical_state(
628+
infcx,
629+
&state.var_values,
630+
max_input_universe,
631+
impl_args,
632+
)),
633+
_ => bug!(),
634+
}
635+
}
617636
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
118118

119119
fn probe_and_match_goal_against_assumption(
120120
ecx: &mut EvalCtxt<'_, 'tcx>,
121-
source: CandidateSource,
121+
source: CandidateSource<'tcx>,
122122
goal: Goal<'tcx, Self>,
123123
assumption: ty::Clause<'tcx>,
124124
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
@@ -182,7 +182,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
182182
ty::ImplPolarity::Positive => {}
183183
};
184184

185-
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
185+
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id, None)).enter(|ecx| {
186186
let impl_args = ecx.fresh_args_for_item(impl_def_id);
187187
let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args);
188188

0 commit comments

Comments
 (0)