Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ use std::iter;
use rustc_index::IndexVec;
use rustc_type_ir::data_structures::HashSet;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::relate::solver_relating::RelateExt;
use rustc_type_ir::{
self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable,
self as ty, Canonical, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, TypeFoldable,
};
use tracing::{debug, instrument, trace};

Expand Down Expand Up @@ -133,6 +134,43 @@ where
),
)
}
(_, Certainty::Yes) => {
let goals = std::mem::take(&mut self.nested_goals);
// As we return all ambiguous nested goals, we can ignore the certainty
// returned by `self.try_evaluate_added_goals()`.
if goals.is_empty() {
assert!(matches!(goals_certainty, Certainty::Yes));
}
if goals.iter().all(|(_, g, _)| {
let Some(clause) = g.predicate.as_clause() else {
return false;
};
match clause.kind().skip_binder() {
ClauseKind::Trait(pred) => {
let def_id = pred.def_id();
(self.cx().is_lang_item(def_id, TraitSolverLangItem::Sized)
|| self
.cx()
.is_lang_item(def_id, TraitSolverLangItem::MetaSized))
&& self.resolve_vars_if_possible(pred).self_ty().is_ty_var()
}
ClauseKind::WellFormed(arg) => {
self.resolve_vars_if_possible(arg).is_infer()
}
_ => false,
}
}) {
(
Certainty::Yes,
NestedNormalizationGoals(
goals.into_iter().map(|(s, g, _)| (s, g)).collect(),
),
)
} else {
let certainty = shallow_certainty.and(goals_certainty);
(certainty, NestedNormalizationGoals::empty())
}
}
_ => {
let certainty = shallow_certainty.and(goals_certainty);
(certainty, NestedNormalizationGoals::empty())
Expand Down
81 changes: 28 additions & 53 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,7 @@ pub trait SolverDelegateEvalExt: SolverDelegate {
&self,
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
span: <Self::Interner as Interner>::Span,
) -> (
Result<
(NestedNormalizationGoals<Self::Interner>, GoalEvaluation<Self::Interner>),
NoSolution,
>,
inspect::GoalEvaluation<Self::Interner>,
);
) -> (Result<GoalEvaluation<Self::Interner>, NoSolution>, inspect::GoalEvaluation<Self::Interner>);
}

impl<D, I> SolverDelegateEvalExt for D
Expand Down Expand Up @@ -221,16 +215,13 @@ where
&self,
goal: Goal<I, I::Predicate>,
span: I::Span,
) -> (
Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution>,
inspect::GoalEvaluation<I>,
) {
) -> (Result<GoalEvaluation<I>, NoSolution>, inspect::GoalEvaluation<I>) {
let (result, proof_tree) = EvalCtxt::enter_root(
self,
self.cx().recursion_limit(),
GenerateProofTree::Yes,
span,
|ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, None),
|ecx| ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, None),
);
(result, proof_tree.unwrap())
}
Expand Down Expand Up @@ -411,26 +402,6 @@ where
goal: Goal<I, I::Predicate>,
stalled_on: Option<GoalStalledOn<I>>,
) -> Result<GoalEvaluation<I>, NoSolution> {
let (normalization_nested_goals, goal_evaluation) =
self.evaluate_goal_raw(goal_evaluation_kind, source, goal, stalled_on)?;
assert!(normalization_nested_goals.is_empty());
Ok(goal_evaluation)
}

/// Recursively evaluates `goal`, returning the nested goals in case
/// the nested goal is a `NormalizesTo` goal.
///
/// As all other goal kinds do not return any nested goals and
/// `NormalizesTo` is only used by `AliasRelate`, all other callsites
/// should use [`EvalCtxt::evaluate_goal`] which discards that empty
/// storage.
pub(super) fn evaluate_goal_raw(
&mut self,
goal_evaluation_kind: GoalEvaluationKind,
source: GoalSource,
goal: Goal<I, I::Predicate>,
stalled_on: Option<GoalStalledOn<I>>,
) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution> {
// If we have run this goal before, and it was stalled, check that any of the goal's
// args have changed. Otherwise, we don't need to re-run the goal because it'll remain
// stalled, since it'll canonicalize the same way and evaluation is pure.
Expand All @@ -441,15 +412,13 @@ where
.opaque_types_storage_num_entries()
.needs_reevaluation(stalled_on.num_opaques)
{
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
goal,
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
},
));
return Ok(GoalEvaluation {
goal,
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
nested_goals: NestedNormalizationGoals::empty(),
});
}

// We only care about one entry per `OpaqueTypeKey` here,
Expand Down Expand Up @@ -477,7 +446,7 @@ where
let has_changed =
if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };

let (normalization_nested_goals, certainty) =
let (nested_goals, certainty) =
self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response);

// FIXME: We previously had an assert here that checked that recomputing
Expand Down Expand Up @@ -536,10 +505,7 @@ where
},
};

Ok((
normalization_nested_goals,
GoalEvaluation { goal, certainty, has_changed, stalled_on },
))
Ok(GoalEvaluation { goal, certainty, has_changed, stalled_on, nested_goals })
}

pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
Expand Down Expand Up @@ -673,10 +639,13 @@ where
let unconstrained_goal =
goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs });

let (
NestedNormalizationGoals(nested_goals),
GoalEvaluation { goal, certainty, stalled_on, has_changed: _ },
) = self.evaluate_goal_raw(
let GoalEvaluation {
goal,
certainty,
stalled_on,
has_changed: _,
nested_goals: NestedNormalizationGoals(nested_goals),
} = self.evaluate_goal(
GoalEvaluationKind::Nested,
source,
unconstrained_goal,
Expand Down Expand Up @@ -733,12 +702,18 @@ where
}
}
} else {
let GoalEvaluation { goal, certainty, has_changed, stalled_on } =
self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?;
let GoalEvaluation {
goal,
certainty,
has_changed,
stalled_on,
nested_goals: NestedNormalizationGoals(nested_goals),
} = self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?;
trace!(?nested_goals);
self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None)));
if has_changed == HasChanged::Yes {
unchanged_certainty = None;
}

match certainty {
Certainty::Yes => {}
Certainty::Maybe(_) => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ pub struct GoalEvaluation<I: Interner> {
/// then reevaluating this goal now only needs to resolve `?y` while it would otherwise
/// have to resolve both `?x` and `?y`,
pub goal: Goal<I, I::Predicate>,
pub nested_goals: NestedNormalizationGoals<I>,
pub certainty: Certainty,
pub has_changed: HasChanged,
/// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed
Expand Down
25 changes: 22 additions & 3 deletions compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ use rustc_hir::def_id::LocalDefId;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::{
FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
FromSolverError, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
TraitEngine,
};
use rustc_middle::ty::{
self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
TypingMode,
};
use rustc_next_trait_solver::delegate::SolverDelegate as _;
use rustc_next_trait_solver::solve::{
GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _,
GoalEvaluation, GoalStalledOn, HasChanged, NestedNormalizationGoals, SolverDelegateEvalExt as _,
};
use rustc_span::Span;
use thin_vec::ThinVec;
Expand Down Expand Up @@ -213,7 +214,13 @@ where

let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
self.inspect_evaluated_obligation(infcx, &obligation, &result);
let GoalEvaluation { goal, certainty, has_changed, stalled_on } = match result {
let GoalEvaluation {
goal,
certainty,
has_changed,
stalled_on,
nested_goals: NestedNormalizationGoals(nested_goals),
} = match result {
Ok(result) => result,
Err(NoSolution) => {
errors.push(E::from_solver_error(
Expand All @@ -223,6 +230,18 @@ where
continue;
}
};
for (_, nested_goal) in nested_goals {
self.obligations.register(
Obligation::with_depth(
infcx.tcx,
ObligationCause::misc(obligation.cause.span, obligation.cause.body_id),
obligation.recursion_depth + 1,
nested_goal.param_env,
nested_goal.predicate,
),
None,
);
}

// We've resolved the goal in `evaluate_root_goal`, avoid redoing this work
// in the next iteration. This does not resolve the inference variables
Expand Down
39 changes: 21 additions & 18 deletions compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit};
use rustc_middle::{bug, ty};
use rustc_next_trait_solver::resolve::eager_resolve_vars;
use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
use rustc_next_trait_solver::solve::{MaybeCause, SolverDelegateEvalExt as _};
use rustc_next_trait_solver::solve::{GoalEvaluation, MaybeCause, SolverDelegateEvalExt as _};
use rustc_span::Span;
use tracing::instrument;

Expand Down Expand Up @@ -249,23 +249,26 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
// `InspectGoal::new` so that the goal has the right result (and maintains
// the impression that we don't do this normalizes-to infer hack at all).
let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span);
let nested_goals_result = nested.and_then(|(nested, _)| {
normalizes_to_term_hack.constrain_and(
infcx,
span,
proof_tree.uncanonicalized_goal.param_env,
|ocx| {
ocx.register_obligations(nested.0.into_iter().map(|(_, goal)| {
Obligation::new(
infcx.tcx,
ObligationCause::dummy_with_span(span),
goal.param_env,
goal.predicate,
)
}));
},
)
});
let nested_goals_result =
nested.and_then(|GoalEvaluation { nested_goals, .. }| {
normalizes_to_term_hack.constrain_and(
infcx,
span,
proof_tree.uncanonicalized_goal.param_env,
|ocx| {
ocx.register_obligations(nested_goals.0.into_iter().map(
|(_, goal)| {
Obligation::new(
infcx.tcx,
ObligationCause::dummy_with_span(span),
goal.param_env,
goal.predicate,
)
},
));
},
)
});
(proof_tree, nested_goals_result)
});
InspectGoal::new(
Expand Down
Loading