From 26ca71fdb2070ae970ea9ce40a52a7b663897940 Mon Sep 17 00:00:00 2001
From: b-naber <bn263@gmx.de>
Date: Tue, 9 Nov 2021 20:21:51 +0100
Subject: [PATCH 1/2] normalize argument b in equate_normalized_inputs_output

---
 .../src/type_check/input_output.rs            | 60 ++++++++++++-------
 compiler/rustc_borrowck/src/type_check/mod.rs |  5 +-
 2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 24332690bec31..92d2d04f23f23 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,13 +7,16 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
+use crate::type_check::constraint_conversion::ConstraintConversion;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::mir::*;
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
-use rustc_trait_selection::traits::query::normalize::AtExt;
+use rustc_span::DUMMY_SP;
+use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
+use rustc_trait_selection::traits::query::Fallible;
+use type_op::TypeOpOutput;
 
 use crate::universal_regions::UniversalRegions;
 
@@ -30,6 +33,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let (&normalized_output_ty, normalized_input_tys) =
             normalized_inputs_and_output.split_last().unwrap();
 
+        debug!(?normalized_output_ty);
+        debug!(?normalized_input_tys);
+
         let mir_def_id = body.source.def_id().expect_local();
 
         // If the user explicitly annotated the input types, extract
@@ -75,10 +81,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
                 break;
             }
+
             // In MIR, argument N is stored in local N+1.
             let local = Local::new(argument_index + 1);
 
             let mir_input_ty = body.local_decls[local].ty;
+
             let mir_input_span = body.local_decls[local].source_info.span;
             self.equate_normalized_input_or_output(
                 normalized_input_ty,
@@ -100,6 +108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // If the user explicitly annotated the input types, enforce those.
                 let user_provided_input_ty =
                     self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
+
                 self.equate_normalized_input_or_output(
                     user_provided_input_ty,
                     mir_input_ty,
@@ -167,30 +176,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
             // like to normalize *before* inserting into `local_decls`, but
             // doing so ends up causing some other trouble.
-            let b = match self
-                .infcx
-                .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
-                .normalize(b)
-            {
-                Ok(n) => {
-                    debug!("equate_inputs_and_outputs: {:?}", n);
-                    if n.obligations.iter().all(|o| {
-                        matches!(
-                            o.predicate.kind().skip_binder(),
-                            ty::PredicateKind::RegionOutlives(_)
-                                | ty::PredicateKind::TypeOutlives(_)
-                        )
-                    }) {
-                        n.value
-                    } else {
-                        b
-                    }
-                }
+            let b = match self.normalize_and_add_constraints(b) {
+                Ok(n) => n,
                 Err(_) => {
                     debug!("equate_inputs_and_outputs: NoSolution");
                     b
                 }
             };
+
             // Note: if we have to introduce new placeholders during normalization above, then we won't have
             // added those universes to the universe info, which we would want in `relate_tys`.
             if let Err(terr) =
@@ -207,4 +200,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
         }
     }
+
+    pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
+        let TypeOpOutput { output: norm_ty, constraints, .. } =
+            self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
+
+        debug!("{:?} normalized to {:?}", t, norm_ty);
+
+        for data in constraints.into_iter().collect::<Vec<_>>() {
+            ConstraintConversion::new(
+                self.infcx,
+                &self.borrowck_context.universal_regions,
+                &self.region_bound_pairs,
+                Some(self.implicit_region_bound),
+                self.param_env,
+                Locations::All(DUMMY_SP),
+                ConstraintCategory::Internal,
+                &mut self.borrowck_context.constraints,
+            )
+            .convert_all(&*data);
+        }
+
+        Ok(norm_ty)
+    }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index ddd077c22faf8..da26d9c7b8779 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -893,11 +893,11 @@ struct TypeChecker<'a, 'tcx> {
 }
 
 struct BorrowCheckContext<'a, 'tcx> {
-    universal_regions: &'a UniversalRegions<'tcx>,
+    pub(crate) universal_regions: &'a UniversalRegions<'tcx>,
     location_table: &'a LocationTable,
     all_facts: &'a mut Option<AllFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
-    constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
+    pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     upvars: &'a [Upvar<'tcx>],
 }
 
@@ -1157,6 +1157,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
     }
 
+    #[instrument(skip(self, category), level = "debug")]
     fn eq_types(
         &mut self,
         expected: Ty<'tcx>,

From 7a4aa65810b1e77f5bbfa442ca36b6fd9530e4be Mon Sep 17 00:00:00 2001
From: b-naber <bn263@gmx.de>
Date: Tue, 9 Nov 2021 20:41:13 +0100
Subject: [PATCH 2/2] add tests

---
 .../normalize-under-binder/issue-90612.rs     | 43 +++++++++++++++++++
 .../normalize-under-binder/issue-90638.rs     | 37 ++++++++++++++++
 2 files changed, 80 insertions(+)
 create mode 100644 src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs
 create mode 100644 src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs

diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs
new file mode 100644
index 0000000000000..e150ecfe9a0dc
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs
@@ -0,0 +1,43 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+trait Family: Sized {
+    type Item<'a>;
+
+    fn apply_all<F>(&self, f: F)
+    where
+        F: FamilyItemFn<Self> { }
+}
+
+struct Array<T>(PhantomData<T>);
+
+impl<T: 'static> Family for Array<T> {
+    type Item<'a> = &'a T;
+}
+
+trait FamilyItemFn<T: Family> {
+    fn apply(&self, item: T::Item<'_>);
+}
+
+impl<T, F> FamilyItemFn<T> for F
+where
+    T: Family,
+    for<'a> F: Fn(T::Item<'a>)
+{
+    fn apply(&self, item: T::Item<'_>) {
+        (*self)(item);
+    }
+}
+
+fn process<T: 'static>(array: Array<T>) {
+    // Works
+    array.apply_all(|x: &T| { });
+
+    // ICE: NoSolution
+    array.apply_all(|x: <Array<T> as Family>::Item<'_>| { });
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs
new file mode 100644
index 0000000000000..18b7f383482a1
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs
@@ -0,0 +1,37 @@
+//check-pass
+
+#![feature(generic_associated_types)]
+
+trait Yokeable<'a>: 'static {
+    type Output: 'a;
+}
+
+trait IsCovariant<'a> {}
+
+struct Yoke<Y: for<'a> Yokeable<'a>> {
+    data: Y,
+}
+
+impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
+    fn project<Y2: for<'a> Yokeable<'a>>(&self, _f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a ())
+      -> <Y2 as Yokeable<'a>>::Output) -> Yoke<Y2> {
+
+        unimplemented!()
+    }
+}
+
+fn _upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
+    Y: for<'a> Yokeable<'a>,
+    for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
+    {
+    x.project(|data, _| {
+        Box::new(data)
+    })
+}
+
+
+impl<'a> Yokeable<'a> for Box<dyn IsCovariant<'static> + 'static> {
+    type Output = Box<dyn IsCovariant<'a> + 'a>;
+}
+
+fn main() {}