From f14a5fd7127af1e774b76deea5a749ced33b23a1 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sat, 25 Dec 2021 22:45:05 -0800
Subject: [PATCH 1/2] check Projection supertrait bounds when confirming dyn
 candidate

---
 .../src/traits/select/confirmation.rs         |  4 ++-
 .../object/enforce-supertrait-projection.rs   | 24 +++++++++++++++++
 .../enforce-supertrait-projection.stderr      | 26 +++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/traits/object/enforce-supertrait-projection.rs
 create mode 100644 src/test/ui/traits/object/enforce-supertrait-projection.stderr

diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index c7e0c35436afb..8fd7664d57885 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -468,7 +468,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .predicates
             .into_iter()
         {
-            if let ty::PredicateKind::Trait(..) = super_trait.kind().skip_binder() {
+            if let ty::PredicateKind::Trait(..) | ty::PredicateKind::Projection(..) =
+                super_trait.kind().skip_binder()
+            {
                 let normalized_super_trait = normalize_with_depth_to(
                     self,
                     obligation.param_env,
diff --git a/src/test/ui/traits/object/enforce-supertrait-projection.rs b/src/test/ui/traits/object/enforce-supertrait-projection.rs
new file mode 100644
index 0000000000000..0ea944ec2df55
--- /dev/null
+++ b/src/test/ui/traits/object/enforce-supertrait-projection.rs
@@ -0,0 +1,24 @@
+trait SuperTrait {
+    type A;
+    type B;
+}
+
+trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
+
+fn transmute<A, B>(x: A) -> B {
+    foo::<A, B, dyn Trait<A = A, B = B>>(x)
+    //~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
+}
+
+fn foo<A, B, T: ?Sized>(x: T::A) -> B
+where
+    T: Trait<B = B>,
+{
+    x
+}
+
+static X: u8 = 0;
+fn main() {
+    let x = transmute::<&u8, &[u8; 1_000_000]>(&X);
+    println!("{:?}", x[100_000]);
+}
diff --git a/src/test/ui/traits/object/enforce-supertrait-projection.stderr b/src/test/ui/traits/object/enforce-supertrait-projection.stderr
new file mode 100644
index 0000000000000..a3d17fabbe47f
--- /dev/null
+++ b/src/test/ui/traits/object/enforce-supertrait-projection.stderr
@@ -0,0 +1,26 @@
+error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
+  --> $DIR/enforce-supertrait-projection.rs:9:5
+   |
+LL | fn transmute<A, B>(x: A) -> B {
+   |              -  - expected type parameter
+   |              |
+   |              found type parameter
+LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A`
+   |
+   = note: expected type parameter `B`
+              found type parameter `A`
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+note: required by a bound in `foo`
+  --> $DIR/enforce-supertrait-projection.rs:15:8
+   |
+LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B
+   |    --- required by a bound in this
+LL | where
+LL |     T: Trait<B = B>,
+   |        ^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.

From 67ef11dc2a64153a381c7b58475a2b65214557af Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Mon, 31 Jan 2022 19:11:23 -0800
Subject: [PATCH 2/2] check all dyn obligations, actually

---
 .../src/traits/select/confirmation.rs         | 30 ++++++++-----------
 .../supertrait-lifetime-bound.nll.stderr      | 11 +++++++
 .../object/supertrait-lifetime-bound.rs       | 20 ++++++-------
 .../object/supertrait-lifetime-bound.stderr   | 15 ++++++++++
 4 files changed, 48 insertions(+), 28 deletions(-)
 create mode 100644 src/test/ui/traits/object/supertrait-lifetime-bound.nll.stderr
 create mode 100644 src/test/ui/traits/object/supertrait-lifetime-bound.stderr

diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 8fd7664d57885..c3f3baf9d3d47 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -468,23 +468,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .predicates
             .into_iter()
         {
-            if let ty::PredicateKind::Trait(..) | ty::PredicateKind::Projection(..) =
-                super_trait.kind().skip_binder()
-            {
-                let normalized_super_trait = normalize_with_depth_to(
-                    self,
-                    obligation.param_env,
-                    obligation.cause.clone(),
-                    obligation.recursion_depth + 1,
-                    super_trait,
-                    &mut nested,
-                );
-                nested.push(Obligation::new(
-                    obligation.cause.clone(),
-                    obligation.param_env,
-                    normalized_super_trait,
-                ));
-            }
+            let normalized_super_trait = normalize_with_depth_to(
+                self,
+                obligation.param_env,
+                obligation.cause.clone(),
+                obligation.recursion_depth + 1,
+                super_trait,
+                &mut nested,
+            );
+            nested.push(Obligation::new(
+                obligation.cause.clone(),
+                obligation.param_env,
+                normalized_super_trait,
+            ));
         }
 
         let assoc_types: Vec<_> = tcx
diff --git a/src/test/ui/traits/object/supertrait-lifetime-bound.nll.stderr b/src/test/ui/traits/object/supertrait-lifetime-bound.nll.stderr
new file mode 100644
index 0000000000000..ed2f8624357bb
--- /dev/null
+++ b/src/test/ui/traits/object/supertrait-lifetime-bound.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/supertrait-lifetime-bound.rs:10:5
+   |
+LL | fn test2<'a>() {
+   |          -- lifetime `'a` defined here
+...
+LL |     test1::<dyn Bar<&'a u32>, _>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/object/supertrait-lifetime-bound.rs b/src/test/ui/traits/object/supertrait-lifetime-bound.rs
index 9d834727a4a1b..5349771693a2a 100644
--- a/src/test/ui/traits/object/supertrait-lifetime-bound.rs
+++ b/src/test/ui/traits/object/supertrait-lifetime-bound.rs
@@ -1,16 +1,14 @@
-// check-pass
+trait Foo: 'static { }
 
-use std::any::Any;
+trait Bar<T>: Foo { }
 
-trait A<T>: Any {
-    fn m(&self) {}
-}
-
-impl<S, T: 'static> A<S> for T {}
+fn test1<T: ?Sized + Bar<S>, S>() { }
 
-fn call_obj<'a>() {
-    let obj: &dyn A<&'a ()> = &();
-    obj.m();
+fn test2<'a>() {
+    // Here: the type `dyn Bar<&'a u32>` references `'a`,
+    // and so it does not outlive `'static`.
+    test1::<dyn Bar<&'a u32>, _>();
+    //~^ ERROR the type `(dyn Bar<&'a u32> + 'static)` does not fulfill the required lifetime
 }
 
-fn main() {}
+fn main() { }
diff --git a/src/test/ui/traits/object/supertrait-lifetime-bound.stderr b/src/test/ui/traits/object/supertrait-lifetime-bound.stderr
new file mode 100644
index 0000000000000..c3d7f8cd0c1cd
--- /dev/null
+++ b/src/test/ui/traits/object/supertrait-lifetime-bound.stderr
@@ -0,0 +1,15 @@
+error[E0477]: the type `(dyn Bar<&'a u32> + 'static)` does not fulfill the required lifetime
+  --> $DIR/supertrait-lifetime-bound.rs:10:5
+   |
+LL |     test1::<dyn Bar<&'a u32>, _>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/supertrait-lifetime-bound.rs:5:22
+   |
+LL | fn test1<T: ?Sized + Bar<S>, S>() { }
+   |                      ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.