about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_infer/src/infer/at.rs25
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs85
4 files changed, 93 insertions, 46 deletions
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 94991fdb201..ff8082840e1 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -28,7 +28,7 @@
 use super::*;
 
 use rustc_middle::ty::relate::{Relate, TypeRelation};
-use rustc_middle::ty::Const;
+use rustc_middle::ty::{Const, ImplSubject};
 
 pub struct At<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'a, 'tcx>,
@@ -272,6 +272,29 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
     }
 }
 
+impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
+    fn to_trace(
+        tcx: TyCtxt<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        match (a, b) {
+            (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
+                ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b)
+            }
+            (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
+                ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b)
+            }
+            (ImplSubject::Trait(_), ImplSubject::Inherent(_))
+            | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
+                bug!("can not trace TraitRef and Ty");
+            }
+        }
+    }
+}
+
 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
     fn to_trace(
         _: TyCtxt<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 91d2d64c52e..3a0019cf92b 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -44,6 +44,7 @@ use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::Align;
 
+use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::ControlFlow;
 use std::{fmt, str};
@@ -172,7 +173,7 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
-#[derive(Debug)]
+#[derive(Copy, Clone, Debug, TypeFoldable)]
 pub enum ImplSubject<'tcx> {
     Trait(TraitRef<'tcx>),
     Inherent(Ty<'tcx>),
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 81ee7942c4d..99cd0c789de 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -7,7 +7,7 @@
 use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
 use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
-use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
 use rustc_span::DUMMY_SP;
@@ -356,6 +356,30 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
     }
 }
 
+impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> {
+    #[inline]
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: ImplSubject<'tcx>,
+        b: ImplSubject<'tcx>,
+    ) -> RelateResult<'tcx, ImplSubject<'tcx>> {
+        match (a, b) {
+            (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
+                let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?;
+                Ok(ImplSubject::Trait(trait_ref))
+            }
+            (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
+                let ty = Ty::relate(relation, ty_a, ty_b)?;
+                Ok(ImplSubject::Inherent(ty))
+            }
+            (ImplSubject::Trait(_), ImplSubject::Inherent(_))
+            | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
+                bug!("can not relate TraitRef and Ty");
+            }
+        }
+    }
+}
+
 impl<'tcx> Relate<'tcx> for Ty<'tcx> {
     #[inline]
     fn relate<R: TypeRelation<'tcx>>(
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 559401c0bd1..7ac6c083076 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -17,7 +17,6 @@ use crate::traits::{
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::CRATE_HIR_ID;
-use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{util, TraitEngine};
 use rustc_middle::traits::specialization_graph::OverlapMode;
@@ -305,72 +304,72 @@ fn negative_impl<'cx, 'tcx>(
     // Create an infcx, taking the predicates of impl1 as assumptions:
     tcx.infer_ctxt().enter(|infcx| {
         // create a parameter environment corresponding to a (placeholder) instantiation of impl1
-        let impl1_env = tcx.param_env(impl1_def_id);
-
-        match tcx.impl_subject(impl1_def_id) {
+        let impl_env = tcx.param_env(impl1_def_id);
+        let subject1 = match tcx.impl_subject(impl1_def_id) {
             ImplSubject::Trait(impl1_trait_ref) => {
-                // Normalize the trait reference. The WF rules ought to ensure
-                // that this always succeeds.
-                let impl1_trait_ref = match traits::fully_normalize(
+                match traits::fully_normalize(
                     &infcx,
                     FulfillmentContext::new(),
                     ObligationCause::dummy(),
-                    impl1_env,
+                    impl_env,
                     impl1_trait_ref,
                 ) {
-                    Ok(impl1_trait_ref) => impl1_trait_ref,
+                    Ok(impl1_trait_ref) => ImplSubject::Trait(impl1_trait_ref),
                     Err(err) => {
                         bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
                     }
-                };
+                }
+            }
+            subject @ ImplSubject::Inherent(_) => subject,
+        };
 
-                // Attempt to prove that impl2 applies, given all of the above.
-                let selcx = &mut SelectionContext::new(&infcx);
-                let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
-                let (impl2_trait_ref, obligations) =
-                    impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs);
+        let (subject2, obligations) =
+            impl_subject_and_obligations(&infcx, impl_env, subject1, impl2_def_id);
 
-                !equate(
-                    &infcx,
-                    impl1_env,
-                    impl1_def_id,
-                    impl1_trait_ref,
-                    impl2_trait_ref,
-                    obligations,
-                )
-            }
-            ImplSubject::Inherent(ty1) => {
-                let ty2 = tcx.type_of(impl2_def_id);
-                !equate(&infcx, impl1_env, impl1_def_id, ty1, ty2, iter::empty())
-            }
-        }
+        !equate(&infcx, impl_env, impl1_def_id, subject1, subject2, obligations)
     })
 }
 
-fn equate<'cx, 'tcx, T: Debug + ToTrace<'tcx>>(
+fn impl_subject_and_obligations<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    impl1_env: ty::ParamEnv<'tcx>,
+    impl_env: ty::ParamEnv<'tcx>,
+    subject1: ImplSubject<'tcx>,
+    impl2_def_id: DefId,
+) -> (ImplSubject<'tcx>, Box<dyn Iterator<Item = PredicateObligation<'tcx>> + 'tcx>) {
+    if let ImplSubject::Trait(_) = subject1 {
+        // Attempt to prove that impl2 applies, given all of the above.
+        let selcx = &mut SelectionContext::new(&infcx);
+        let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
+        let (impl2_trait_ref, obligations) =
+            impl_trait_ref_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
+
+        (ImplSubject::Trait(impl2_trait_ref), Box::new(obligations))
+    } else {
+        (infcx.tcx.impl_subject(impl2_def_id), Box::new(iter::empty()))
+    }
+}
+
+fn equate<'cx, 'tcx>(
+    infcx: &InferCtxt<'cx, 'tcx>,
+    impl_env: ty::ParamEnv<'tcx>,
     impl1_def_id: DefId,
-    impl1: T,
-    impl2: T,
+    subject1: ImplSubject<'tcx>,
+    subject2: ImplSubject<'tcx>,
     obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
 ) -> bool {
     // do the impls unify? If not, not disjoint.
-    let Ok(InferOk { obligations: more_obligations, .. }) = infcx
-        .at(&ObligationCause::dummy(), impl1_env)
-        .eq(impl1, impl2) else {
-            debug!(
-                "explicit_disjoint: {:?} does not unify with {:?}",
-                impl1, impl2
-            );
-            return true;
-        };
+    let Ok(InferOk { obligations: more_obligations, .. }) =
+        infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2)
+    else {
+        debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
+        return true;
+    };
 
     let selcx = &mut SelectionContext::new(&infcx);
     let opt_failing_obligation = obligations
         .into_iter()
         .chain(more_obligations)
-        .find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
+        .find(|o| negative_impl_exists(selcx, impl_env, impl1_def_id, o));
 
     if let Some(failing_obligation) = opt_failing_obligation {
         debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);