From d96faef9138d6618e36fec1919e1c9305fefa96c Mon Sep 17 00:00:00 2001
From: Santiago Pastorino <spastorino@gmail.com>
Date: Thu, 24 Mar 2022 17:47:10 -0300
Subject: [PATCH] Where bounds are checked on inherent impls

---
 .../src/traits/coherence.rs                   | 10 +++++--
 .../rustc_trait_selection/src/traits/util.rs  | 28 +++++++++++++++++++
 ...oherence-negative-inherent-where-bounds.rs | 25 +++++++++++++++++
 3 files changed, 61 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/coherence/coherence-negative-inherent-where-bounds.rs

diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index f3385df513f..ed9ddb51834 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -7,7 +7,7 @@
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{CombinedSnapshot, InferOk, RegionckMode};
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::util::impl_trait_ref_and_oblig;
+use crate::traits::util::{impl_trait_ref_and_oblig, inherent_impl_and_oblig};
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
     self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
@@ -338,7 +338,13 @@ fn impl_subject_and_obligations<'cx, 'tcx>(
 
         (ImplSubject::Trait(impl2_trait_ref), Box::new(obligations))
     } else {
-        (infcx.tcx.impl_subject(impl2_def_id), Box::new(iter::empty()))
+        // 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_ty, obligations) =
+            inherent_impl_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
+
+        (ImplSubject::Inherent(impl2_ty), Box::new(obligations))
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index f800e7a1402..7b64deac99d 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -218,6 +218,34 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>(
     (impl_trait_ref, impl_obligations)
 }
 
+/// Instantiate all bound parameters of the impl with the given substs,
+/// returning the resulting trait ref and all obligations that arise.
+/// The obligations are closed under normalization.
+pub fn inherent_impl_and_oblig<'a, 'tcx>(
+    selcx: &mut SelectionContext<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    impl_def_id: DefId,
+    impl_substs: SubstsRef<'tcx>,
+) -> (Ty<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
+    let ty = selcx.tcx().type_of(impl_def_id);
+    let ty = ty.subst(selcx.tcx(), impl_substs);
+    let Normalized { value: ty, obligations: normalization_obligations1 } =
+        super::normalize(selcx, param_env, ObligationCause::dummy(), ty);
+
+    let predicates = selcx.tcx().predicates_of(impl_def_id);
+    let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
+    let Normalized { value: predicates, obligations: normalization_obligations2 } =
+        super::normalize(selcx, param_env, ObligationCause::dummy(), predicates);
+    let impl_obligations =
+        predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates);
+
+    let impl_obligations = impl_obligations
+        .chain(normalization_obligations1.into_iter())
+        .chain(normalization_obligations2.into_iter());
+
+    (ty, impl_obligations)
+}
+
 pub fn predicates_for_generics<'tcx>(
     cause: ObligationCause<'tcx>,
     recursion_depth: usize,
diff --git a/src/test/ui/coherence/coherence-negative-inherent-where-bounds.rs b/src/test/ui/coherence/coherence-negative-inherent-where-bounds.rs
new file mode 100644
index 00000000000..39ccaa6ac35
--- /dev/null
+++ b/src/test/ui/coherence/coherence-negative-inherent-where-bounds.rs
@@ -0,0 +1,25 @@
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(with_negative_coherence)]
+
+trait Foo {}
+
+impl !Foo for u32 {}
+
+#[rustc_strict_coherence]
+struct MyStruct<T>(T);
+
+impl MyStruct<u32> {
+    fn method(&self) {}
+}
+
+impl<T> MyStruct<T>
+where
+    T: Foo,
+{
+    fn method(&self) {}
+}
+
+fn main() {}