about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-31 17:36:11 +0000
committerbors <bors@rust-lang.org>2022-01-31 17:36:11 +0000
commit498eeb72f590e518e19746b346be53713689e207 (patch)
tree2c2e49bd9abfcfa662cfb75ea9cd2428885657d3 /compiler/rustc_trait_selection/src
parent24b8bb13bff98bb747cd403b86596af43aceee78 (diff)
parent0decf14ef1e63e7e7b70805cdf3d03b42d2f457c (diff)
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
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs73
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs14
3 files changed, 30 insertions, 60 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index ab1dc8fcbfe..21775a5c49f 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -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)
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 2c5e7e40cc8..b098e8590da 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -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),
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 3ac273fd19b..5ee8b45e66b 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -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) => {