Skip to content
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

Make proof tree probing and Candidate/CandidateSource generic over interner #126496

Merged
merged 2 commits into from
Jun 15, 2024
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
4 changes: 4 additions & 0 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
{
self.resolve_vars_if_possible(value)
}

fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
self.probe(|_| probe())
}
}

/// See the `error_reporting` module for more details.
Expand Down
99 changes: 50 additions & 49 deletions compiler/rustc_trait_selection/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
//! Code shared by trait and projection goals for candidate assembly.

use derivative::Derivative;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution;
use rustc_middle::bug;
use rustc_middle::traits::solve::inspect::ProbeKind;
use rustc_middle::traits::solve::{
CandidateSource, CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult,
};
use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{fast_reject, TypeFoldable};
use rustc_middle::ty::{TypeVisitableExt, Upcast};
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
use std::fmt::Debug;
use rustc_type_ir::solve::{CandidateSource, CanonicalResponse};
use rustc_type_ir::Interner;

use crate::solve::GoalSource;
use crate::solve::{EvalCtxt, SolverMode};
Expand All @@ -25,10 +25,11 @@ pub(super) mod structural_traits;
///
/// It consists of both the `source`, which describes how that goal would be proven,
/// and the `result` when using the given `source`.
#[derive(Debug, Clone)]
pub(super) struct Candidate<'tcx> {
pub(super) source: CandidateSource<'tcx>,
pub(super) result: CanonicalResponse<'tcx>,
#[derive(Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
pub(super) struct Candidate<I: Interner> {
pub(super) source: CandidateSource<I>,
pub(super) result: CanonicalResponse<I>,
}

/// Methods used to assemble candidates for either trait or projection goals.
Expand All @@ -49,22 +50,22 @@ pub(super) trait GoalKind<'tcx>:
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
source: CandidateSource<'tcx>,
source: CandidateSource<TyCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// Consider a clause, which consists of a "assumption" and some "requirements",
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
/// goal by equating it with the assumption.
fn probe_and_consider_implied_clause(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
parent_source: CandidateSource<'tcx>,
parent_source: CandidateSource<TyCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
) -> Result<Candidate<'tcx>, NoSolution> {
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| {
for (nested_source, goal) in requirements {
ecx.add_goal(nested_source, goal);
Expand All @@ -78,10 +79,10 @@ pub(super) trait GoalKind<'tcx>:
/// since they're not implied by the well-formedness of the object type.
fn probe_and_consider_object_bound_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
source: CandidateSource<'tcx>,
source: CandidateSource<TyCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
) -> Result<Candidate<'tcx>, NoSolution> {
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
let tcx = ecx.interner();
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
Expand All @@ -104,7 +105,7 @@ pub(super) trait GoalKind<'tcx>:
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
impl_def_id: DefId,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// If the predicate contained an error, we want to avoid emitting unnecessary trait
/// errors but still want to emit errors for other trait goals. We have some special
Expand All @@ -115,7 +116,7 @@ pub(super) trait GoalKind<'tcx>:
fn consider_error_guaranteed_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
guar: ErrorGuaranteed,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A type implements an `auto trait` if its components do as well.
///
Expand All @@ -124,13 +125,13 @@ pub(super) trait GoalKind<'tcx>:
fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A trait alias holds if the RHS traits and `where` clauses hold.
fn consider_trait_alias_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A type is `Sized` if its tail component is `Sized`.
///
Expand All @@ -139,7 +140,7 @@ pub(super) trait GoalKind<'tcx>:
fn consider_builtin_sized_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
///
Expand All @@ -148,50 +149,50 @@ pub(super) trait GoalKind<'tcx>:
fn consider_builtin_copy_clone_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A type is `PointerLike` if we can compute its layout, and that layout
/// matches the layout of `usize`.
fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A type is a `FnPtr` if it is of `FnPtr` type.
fn consider_builtin_fn_ptr_trait_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
/// family of traits where `A` is given by the signature of the type.
fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
kind: ty::ClosureKind,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// An async closure is known to implement the `AsyncFn<A>` family of traits
/// where `A` is given by the signature of the type.
fn consider_builtin_async_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
kind: ty::ClosureKind,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
/// is used internally to delay computation for async closures until after
/// upvar analysis is performed in HIR typeck.
fn consider_builtin_async_fn_kind_helper_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// `Tuple` is implemented if the `Self` type is a tuple.
fn consider_builtin_tuple_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// `Pointee` is always implemented.
///
Expand All @@ -201,63 +202,63 @@ pub(super) trait GoalKind<'tcx>:
fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A coroutine (that comes from an `async` desugaring) is known to implement
/// `Future<Output = O>`, where `O` is given by the coroutine's return type
/// that was computed during type-checking.
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A coroutine (that comes from a `gen` desugaring) is known to implement
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
/// that was computed during type-checking.
fn consider_builtin_iterator_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A coroutine (that comes from a `gen` desugaring) is known to implement
/// `FusedIterator`
fn consider_builtin_fused_iterator_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

fn consider_builtin_async_iterator_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
/// and return types of the coroutine computed during type-checking.
fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

fn consider_builtin_async_destruct_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

fn consider_builtin_destruct_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

fn consider_builtin_transmute_candidate(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<'tcx>, NoSolution>;
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;

/// Consider (possibly several) candidates to upcast or unsize a type to another
/// type, excluding the coercion of a sized type into a `dyn Trait`.
Expand All @@ -269,14 +270,14 @@ pub(super) trait GoalKind<'tcx>:
fn consider_structural_builtin_unsize_candidates(
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Vec<Candidate<'tcx>>;
) -> Vec<Candidate<TyCtxt<'tcx>>>;
}

impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
) -> Vec<Candidate<'tcx>> {
) -> Vec<Candidate<TyCtxt<'tcx>>> {
let Ok(normalized_self_ty) =
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
else {
Expand Down Expand Up @@ -323,7 +324,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
pub(super) fn forced_ambiguity(
&mut self,
cause: MaybeCause,
) -> Result<Candidate<'tcx>, NoSolution> {
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
// This may fail if `try_evaluate_added_goals` overflows because it
// fails to reach a fixpoint but ends up getting an error after
// running for some additional step.
Expand All @@ -339,7 +340,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let tcx = self.interner();
let self_ty = goal.predicate.self_ty();
Expand Down Expand Up @@ -455,7 +456,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let tcx = self.interner();
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
Expand All @@ -478,7 +479,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let tcx = self.interner();
let lang_items = tcx.lang_items();
Expand Down Expand Up @@ -552,7 +553,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn assemble_param_env_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
candidates.extend(G::probe_and_consider_implied_clause(
Expand All @@ -569,7 +570,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
Expand All @@ -589,7 +590,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
&mut self,
self_ty: Ty<'tcx>,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let (kind, alias_ty) = match *self_ty.kind() {
ty::Bool
Expand Down Expand Up @@ -673,7 +674,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let tcx = self.interner();
if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object {
Expand Down Expand Up @@ -764,7 +765,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let tcx = self.interner();

Expand Down Expand Up @@ -793,7 +794,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn discard_impls_shadowed_by_env<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let tcx = self.interner();
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
Expand Down Expand Up @@ -841,7 +842,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_candidates(
&mut self,
candidates: Vec<Candidate<'tcx>>,
candidates: Vec<Candidate<TyCtxt<'tcx>>>,
) -> QueryResult<'tcx> {
// First try merging all candidates. This is complete and fully sound.
let responses = candidates.iter().map(|c| c.result).collect::<Vec<_>>();
Expand Down
Loading
Loading