Auto merge of #93348 - spastorino:fix-perf-overlap-mode2, r=nikomatsakis
Move overlap_mode into trait level attribute r? `@nikomatsakis` Should fix some performance regressions noted on https://github.com/rust-lang/rust/pull/93175
This commit is contained in:
commit
498eeb72f5
17 changed files with 111 additions and 75 deletions
|
@ -13,8 +13,8 @@ use crate::traits::{
|
|||
self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
|
||||
PredicateObligations, SelectionContext,
|
||||
};
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||
use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
|
@ -62,6 +62,7 @@ pub fn overlapping_impls<F1, F2, R>(
|
|||
impl1_def_id: DefId,
|
||||
impl2_def_id: DefId,
|
||||
skip_leak_check: SkipLeakCheck,
|
||||
overlap_mode: OverlapMode,
|
||||
on_overlap: F1,
|
||||
no_overlap: F2,
|
||||
) -> R
|
||||
|
@ -99,7 +100,7 @@ where
|
|||
|
||||
let overlaps = tcx.infer_ctxt().enter(|infcx| {
|
||||
let selcx = &mut SelectionContext::intercrate(&infcx);
|
||||
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some()
|
||||
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
|
||||
});
|
||||
|
||||
if !overlaps {
|
||||
|
@ -112,7 +113,9 @@ where
|
|||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let selcx = &mut SelectionContext::intercrate(&infcx);
|
||||
selcx.enable_tracking_intercrate_ambiguity_causes();
|
||||
on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap())
|
||||
on_overlap(
|
||||
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -138,56 +141,6 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
|
|||
header
|
||||
}
|
||||
|
||||
/// What kind of overlap check are we doing -- this exists just for testing and feature-gating
|
||||
/// purposes.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
enum OverlapMode {
|
||||
/// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)
|
||||
Stable,
|
||||
/// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.
|
||||
WithNegative,
|
||||
/// Just check for negative impls, not for "where clause not implemented": used for testing.
|
||||
Strict,
|
||||
}
|
||||
|
||||
impl OverlapMode {
|
||||
fn use_negative_impl(&self) -> bool {
|
||||
*self == OverlapMode::Strict || *self == OverlapMode::WithNegative
|
||||
}
|
||||
|
||||
fn use_implicit_negative(&self) -> bool {
|
||||
*self == OverlapMode::Stable || *self == OverlapMode::WithNegative
|
||||
}
|
||||
}
|
||||
|
||||
fn overlap_mode<'tcx>(tcx: TyCtxt<'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) -> OverlapMode {
|
||||
// Find the possible coherence mode override opt-in attributes for each `DefId`
|
||||
let find_coherence_attr = |attr: &Attribute| {
|
||||
let name = attr.name_or_empty();
|
||||
match name {
|
||||
sym::rustc_with_negative_coherence | sym::rustc_strict_coherence => Some(name),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
let impl1_coherence_mode = tcx.get_attrs(impl1_def_id).iter().find_map(find_coherence_attr);
|
||||
let impl2_coherence_mode = tcx.get_attrs(impl2_def_id).iter().find_map(find_coherence_attr);
|
||||
|
||||
// If there are any (that currently happens in tests), they need to match. Otherwise, the
|
||||
// default 1.0 rules are used.
|
||||
match (impl1_coherence_mode, impl2_coherence_mode) {
|
||||
(None, None) => OverlapMode::Stable,
|
||||
(Some(sym::rustc_with_negative_coherence), Some(sym::rustc_with_negative_coherence)) => {
|
||||
OverlapMode::WithNegative
|
||||
}
|
||||
(Some(sym::rustc_strict_coherence), Some(sym::rustc_strict_coherence)) => {
|
||||
OverlapMode::Strict
|
||||
}
|
||||
(Some(mode), _) | (_, Some(mode)) => {
|
||||
bug!("Use the same coherence mode on both impls: {}", mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Can both impl `a` and impl `b` be satisfied by a common type (including
|
||||
/// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls.
|
||||
fn overlap<'cx, 'tcx>(
|
||||
|
@ -195,11 +148,19 @@ fn overlap<'cx, 'tcx>(
|
|||
skip_leak_check: SkipLeakCheck,
|
||||
impl1_def_id: DefId,
|
||||
impl2_def_id: DefId,
|
||||
overlap_mode: OverlapMode,
|
||||
) -> Option<OverlapResult<'tcx>> {
|
||||
debug!("overlap(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
|
||||
|
||||
selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
|
||||
overlap_within_probe(selcx, skip_leak_check, impl1_def_id, impl2_def_id, snapshot)
|
||||
overlap_within_probe(
|
||||
selcx,
|
||||
skip_leak_check,
|
||||
impl1_def_id,
|
||||
impl2_def_id,
|
||||
overlap_mode,
|
||||
snapshot,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -208,12 +169,10 @@ fn overlap_within_probe<'cx, 'tcx>(
|
|||
skip_leak_check: SkipLeakCheck,
|
||||
impl1_def_id: DefId,
|
||||
impl2_def_id: DefId,
|
||||
overlap_mode: OverlapMode,
|
||||
snapshot: &CombinedSnapshot<'_, 'tcx>,
|
||||
) -> Option<OverlapResult<'tcx>> {
|
||||
let infcx = selcx.infcx();
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
let overlap_mode = overlap_mode(tcx, impl1_def_id, impl2_def_id);
|
||||
|
||||
if overlap_mode.use_negative_impl() {
|
||||
if negative_impl(selcx, impl1_def_id, impl2_def_id)
|
||||
|
|
|
@ -257,6 +257,7 @@ pub(super) fn specialization_graph_provider(
|
|||
trait_id: DefId,
|
||||
) -> specialization_graph::Graph {
|
||||
let mut sg = specialization_graph::Graph::new();
|
||||
let overlap_mode = specialization_graph::OverlapMode::get(tcx, trait_id);
|
||||
|
||||
let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect();
|
||||
|
||||
|
@ -270,7 +271,7 @@ pub(super) fn specialization_graph_provider(
|
|||
for impl_def_id in trait_impls {
|
||||
if let Some(impl_def_id) = impl_def_id.as_local() {
|
||||
// This is where impl overlap checking happens:
|
||||
let insert_result = sg.insert(tcx, impl_def_id.to_def_id());
|
||||
let insert_result = sg.insert(tcx, impl_def_id.to_def_id(), overlap_mode);
|
||||
// Report error if there was one.
|
||||
let (overlap, used_to_be_allowed) = match insert_result {
|
||||
Err(overlap) => (Some(overlap), None),
|
||||
|
|
|
@ -41,6 +41,7 @@ trait ChildrenExt<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
impl_def_id: DefId,
|
||||
simplified_self: Option<SimplifiedType>,
|
||||
overlap_mode: OverlapMode,
|
||||
) -> Result<Inserted, OverlapError>;
|
||||
}
|
||||
|
||||
|
@ -92,6 +93,7 @@ impl ChildrenExt<'_> for Children {
|
|||
tcx: TyCtxt<'_>,
|
||||
impl_def_id: DefId,
|
||||
simplified_self: Option<SimplifiedType>,
|
||||
overlap_mode: OverlapMode,
|
||||
) -> Result<Inserted, OverlapError> {
|
||||
let mut last_lint = None;
|
||||
let mut replace_children = Vec::new();
|
||||
|
@ -142,6 +144,7 @@ impl ChildrenExt<'_> for Children {
|
|||
possible_sibling,
|
||||
impl_def_id,
|
||||
traits::SkipLeakCheck::default(),
|
||||
overlap_mode,
|
||||
|_| true,
|
||||
|| false,
|
||||
);
|
||||
|
@ -166,6 +169,7 @@ impl ChildrenExt<'_> for Children {
|
|||
possible_sibling,
|
||||
impl_def_id,
|
||||
traits::SkipLeakCheck::Yes,
|
||||
overlap_mode,
|
||||
|overlap| {
|
||||
if let Some(overlap_kind) =
|
||||
tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
|
||||
|
@ -273,6 +277,7 @@ pub trait GraphExt {
|
|||
&mut self,
|
||||
tcx: TyCtxt<'_>,
|
||||
impl_def_id: DefId,
|
||||
overlap_mode: OverlapMode,
|
||||
) -> Result<Option<FutureCompatOverlapError>, OverlapError>;
|
||||
|
||||
/// Insert cached metadata mapping from a child impl back to its parent.
|
||||
|
@ -287,6 +292,7 @@ impl GraphExt for Graph {
|
|||
&mut self,
|
||||
tcx: TyCtxt<'_>,
|
||||
impl_def_id: DefId,
|
||||
overlap_mode: OverlapMode,
|
||||
) -> Result<Option<FutureCompatOverlapError>, OverlapError> {
|
||||
assert!(impl_def_id.is_local());
|
||||
|
||||
|
@ -327,8 +333,12 @@ impl GraphExt for Graph {
|
|||
loop {
|
||||
use self::Inserted::*;
|
||||
|
||||
let insert_result =
|
||||
self.children.entry(parent).or_default().insert(tcx, impl_def_id, simplified)?;
|
||||
let insert_result = self.children.entry(parent).or_default().insert(
|
||||
tcx,
|
||||
impl_def_id,
|
||||
simplified,
|
||||
overlap_mode,
|
||||
)?;
|
||||
|
||||
match insert_result {
|
||||
BecameNewSibling(opt_lint) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue