Skip to content
Draft
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
34 changes: 33 additions & 1 deletion compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query};
use rustc_macros::Diagnostic;
use rustc_middle::middle::stability;
use rustc_middle::ty::elaborate::supertrait_def_ids;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, SimplifiedType, TreatParams, simplify_type};
use rustc_middle::ty::{
self, AssocContainer, AssocItem, GenericArgs, GenericArgsRef, GenericParamDefKind, ParamEnvAnd,
Ty, TyCtxt, TypeVisitableExt, Unnormalized, Upcast,
Expand Down Expand Up @@ -1709,6 +1709,36 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
None
}

/// A cheap pre-filter: if both the receiver type and the candidate
/// method's declared self type simplify to concrete, different type
/// heads, the full `consider_probe` relation cannot succeed. This makes
/// the by-value probe pass nearly free for `&self`/`&mut self` methods —
/// the overwhelmingly common kind — which would otherwise pay for a
/// snapshot, fresh args and normalization per candidate just to fail the
/// self type unification.
fn candidate_self_head_may_unify(
&self,
self_ty_head: Option<SimplifiedType>,
candidate: &Candidate<'tcx>,
) -> bool {
// Only method-call probes relate the receiver against the method's
// transformed self type; path probes (UFCS) relate against the
// impl's self type, where the method's own self shape is irrelevant.
if self.mode != Mode::MethodCall {
return true;
}
let Some(self_ty_head) = self_ty_head else { return true };
if !candidate.item.is_method() {
return true;
}
let declared_self =
self.tcx.fn_sig(candidate.item.def_id).skip_binder().skip_binder().inputs()[0];
match simplify_type(self.tcx, declared_self, TreatParams::InstantiateWithInfer) {
Some(declared_head) => declared_head == self_ty_head,
None => true,
}
}

fn consider_candidates(
&self,
self_ty: Ty<'tcx>,
Expand All @@ -1717,13 +1747,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
pick_constraints: Option<&PickConstraintsForShadowed>,
) -> Option<PickResult<'tcx>> {
let self_ty_head = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer);
let mut applicable_candidates: Vec<_> = candidates
.iter()
.filter(|candidate| {
pick_constraints
.map(|pick_constraints| pick_constraints.candidate_may_shadow(&candidate))
.unwrap_or(true)
})
.filter(|candidate| self.candidate_self_head_may_unify(self_ty_head, candidate))
.map(|probe| {
(
probe,
Expand Down
Loading