Skip to content

Clear nested candidates in select if certainty is yes #141927

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 53 additions & 28 deletions compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,45 +133,25 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
/// Instantiate the nested goals for the candidate without rolling back their
/// inference constraints. This function modifies the state of the `infcx`.
///
/// See [`Self::instantiate_nested_goals_and_opt_impl_args`] if you need the impl args too.
pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> {
self.instantiate_nested_goals_and_opt_impl_args(span).0
}

/// Instantiate the nested goals for the candidate without rolling back their
/// inference constraints, and optionally the args of an impl if this candidate
/// came from a `CandidateSource::Impl`. This function modifies the state of the
/// `infcx`.
/// See [`Self::instantiate_impl_args`] if you need the impl args too.
#[instrument(
level = "debug",
skip_all,
fields(goal = ?self.goal.goal, steps = ?self.steps)
)]
pub fn instantiate_nested_goals_and_opt_impl_args(
&self,
span: Span,
) -> (Vec<InspectGoal<'a, 'tcx>>, Option<ty::GenericArgsRef<'tcx>>) {
pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> {
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.to_vec();

let mut instantiated_goals = vec![];
let mut opt_impl_args = None;
for step in &self.steps {
match **step {
inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
source,
instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal),
)),
inspect::ProbeStep::RecordImplArgs { impl_args } => {
opt_impl_args = Some(instantiate_canonical_state(
infcx,
span,
param_env,
&mut orig_values,
impl_args,
));
}
inspect::ProbeStep::RecordImplArgs { .. } => {}
inspect::ProbeStep::MakeCanonicalResponse { .. }
| inspect::ProbeStep::NestedProbe(_) => unreachable!(),
}
Expand All @@ -187,14 +167,59 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
let _ = term_hack.constrain(infcx, span, param_env);
}

let opt_impl_args = opt_impl_args.map(|impl_args| eager_resolve_vars(infcx, impl_args));

let goals = instantiated_goals
instantiated_goals
.into_iter()
.map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
.collect();
.collect()
}

/// Instantiate the args of an impl if this candidate came from a
/// `CandidateSource::Impl`. This function modifies the state of the
/// `infcx`.
#[instrument(
level = "debug",
skip_all,
fields(goal = ?self.goal.goal, steps = ?self.steps)
)]
pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> {
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.to_vec();

for step in &self.steps {
match **step {
inspect::ProbeStep::RecordImplArgs { impl_args } => {
let impl_args = instantiate_canonical_state(
infcx,
span,
param_env,
&mut orig_values,
impl_args,
);

let () = instantiate_canonical_state(
infcx,
span,
param_env,
&mut orig_values,
self.final_state,
);

// No reason we couldn't support this, but we don't need to for select.
assert!(
self.goal.normalizes_to_term_hack.is_none(),
"cannot use `instantiate_impl_args` with a `NormalizesTo` goal"
);

return eager_resolve_vars(infcx, impl_args);
}
inspect::ProbeStep::AddGoal(..) => {}
inspect::ProbeStep::MakeCanonicalResponse { .. }
| inspect::ProbeStep::NestedProbe(_) => unreachable!(),
}
}

(goals, opt_impl_args)
bug!("expected impl args probe step for `instantiate_impl_args`");
}

pub fn instantiate_proof_tree_for_nested_goal(
Expand Down
30 changes: 17 additions & 13 deletions compiler/rustc_trait_selection/src/solve/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_infer::traits::{
use rustc_macros::extension;
use rustc_middle::{bug, span_bug};
use rustc_span::Span;
use thin_vec::thin_vec;

use crate::solve::inspect::{self, ProofTreeInferCtxtExt};

Expand Down Expand Up @@ -146,18 +147,21 @@ fn to_selection<'tcx>(
return None;
}

let (nested, impl_args) = cand.instantiate_nested_goals_and_opt_impl_args(span);
let nested = nested
.into_iter()
.map(|nested| {
Obligation::new(
nested.infcx().tcx,
ObligationCause::dummy_with_span(span),
nested.goal().param_env,
nested.goal().predicate,
)
})
.collect();
let nested = match cand.result().expect("expected positive result") {
Certainty::Yes => thin_vec![],
Certainty::Maybe(_) => cand
.instantiate_nested_goals(span)
.into_iter()
.map(|nested| {
Obligation::new(
nested.infcx().tcx,
ObligationCause::dummy_with_span(span),
nested.goal().param_env,
nested.goal().predicate,
)
})
.collect(),
};

Some(match cand.kind() {
ProbeKind::TraitCandidate { source, result: _ } => match source {
Expand All @@ -166,7 +170,7 @@ fn to_selection<'tcx>(
// For impl candidates, we do the rematch manually to compute the args.
ImplSource::UserDefined(ImplSourceUserDefinedData {
impl_def_id,
args: impl_args.expect("expected recorded impl args for impl candidate"),
args: cand.instantiate_impl_args(span),
nested,
})
}
Expand Down
Loading