about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs54
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs20
-rw-r--r--src/test/ui/feature-gates/feature-gate-trait_upcasting.rs13
-rw-r--r--src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr12
-rw-r--r--src/test/ui/issues/issue-11515.rs4
-rw-r--r--src/test/ui/issues/issue-11515.stderr10
-rw-r--r--src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs13
-rw-r--r--src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs22
-rw-r--r--src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr14
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-1.rs33
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr80
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-2.rs34
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr61
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-3.rs22
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr33
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-4.rs32
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr47
20 files changed, 504 insertions, 27 deletions
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 1ec9a0518b8..638330c904d 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -683,6 +683,10 @@ declare_features! (
     /// Allows the `?` operator in const contexts.
     (active, const_try, "1.56.0", Some(74935), None),
 
+    /// Allows upcasting trait objects via supertraits.
+    /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
+    (incomplete, trait_upcasting, "1.56.0", Some(65991), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 295e53aba35..1ac489f600a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1270,6 +1270,7 @@ symbols! {
         trace_macros,
         track_caller,
         trait_alias,
+        trait_upcasting,
         transmute,
         transparent,
         transparent_enums,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 752f6a8debc..c7bf1f2a943 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -693,22 +693,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let may_apply = match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
             (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
-                // Upcasts permit two things:
-                //
-                // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
-                // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
-                //
-                // Note that neither of these changes requires any
-                // change at runtime. Eventually this will be
-                // generalized.
-                //
-                // We always upcast when we can because of reason
-                // #2 (region bounds).
-                data_a.principal_def_id() == data_b.principal_def_id()
-                    && data_b
-                        .auto_traits()
-                        // All of a's auto traits need to be in b's auto traits.
-                        .all(|b| data_a.auto_traits().any(|a| a == b))
+                // See `confirm_builtin_unsize_candidate` for more info.
+                let auto_traits_compatible = data_b
+                    .auto_traits()
+                    // All of a's auto traits need to be in b's auto traits.
+                    .all(|b| data_a.auto_traits().any(|a| a == b));
+                auto_traits_compatible
             }
 
             // `T` -> `Trait`
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index f8297ee3a07..0c2099593a2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -703,10 +703,56 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
             (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
-                // See `assemble_candidates_for_unsizing` for more info.
-                let iter = data_a
-                    .principal()
-                    .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
+                // Upcast coercions permit several things:
+                //
+                // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
+                // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
+                // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
+                //
+                // Note that neither of the first two of these changes requires any
+                // change at runtime. The third needs to change pointer metadata at runtime.
+                //
+                // We always perform upcasting coercions when we can because of reason
+                // #2 (region bounds).
+
+                // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
+
+                let principal_a = data_a.principal();
+                let principal_def_id_b = data_b.principal_def_id();
+
+                let existential_predicate = if let Some(principal_a) = principal_a {
+                    let source_trait_ref = principal_a.with_self_ty(tcx, source);
+                    let target_trait_did = principal_def_id_b.ok_or_else(|| Unimplemented)?;
+                    let upcast_idx = util::supertraits(tcx, source_trait_ref)
+                        .position(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
+                        .ok_or_else(|| Unimplemented)?;
+                    // FIXME(crlf0710): This is less than ideal, for example,
+                    // if the trait is defined as `trait Foo: Bar<u32> + Bar<i32>`,
+                    // the coercion from Box<Foo> to Box<dyn Bar<_>> is actually ambiguous.
+                    // We currently make this coercion fail for now.
+                    //
+                    // see #65991 for more information.
+                    if util::supertraits(tcx, source_trait_ref)
+                        .skip(upcast_idx + 1)
+                        .any(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
+                    {
+                        return Err(Unimplemented);
+                    }
+                    let target_trait_ref =
+                        util::supertraits(tcx, source_trait_ref).nth(upcast_idx).unwrap();
+                    let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
+                        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
+                            tcx, trait_ref,
+                        ))
+                    });
+                    Some(existential_predicate)
+                } else if principal_def_id_b.is_none() {
+                    None
+                } else {
+                    return Err(Unimplemented);
+                };
+
+                let iter = existential_predicate
                     .into_iter()
                     .chain(
                         data_a
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index ba76b9c8dd5..a83b39a1108 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -576,6 +576,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         )];
 
         let mut has_unsized_tuple_coercion = false;
+        let mut has_trait_upcasting_coercion = false;
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -590,7 +591,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     if traits.contains(&trait_pred.def_id()) =>
                 {
                     if unsize_did == trait_pred.def_id() {
+                        let self_ty = trait_pred.self_ty();
                         let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
+                        if let (ty::Dynamic(ref data_a, ..), ty::Dynamic(ref data_b, ..)) =
+                            (self_ty.kind(), unsize_ty.kind())
+                        {
+                            if data_a.principal_def_id() != data_b.principal_def_id() {
+                                debug!("coerce_unsized: found trait upcasting coercion");
+                                has_trait_upcasting_coercion = true;
+                            }
+                        }
                         if let ty::Tuple(..) = unsize_ty.kind() {
                             debug!("coerce_unsized: found unsized tuple coercion");
                             has_unsized_tuple_coercion = true;
@@ -666,6 +676,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             .emit();
         }
 
+        if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting {
+            feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::trait_upcasting,
+                self.cause.span,
+                "trait upcasting coercion is experimental",
+            )
+            .emit();
+        }
+
         Ok(coercion)
     }
 
diff --git a/src/test/ui/feature-gates/feature-gate-trait_upcasting.rs b/src/test/ui/feature-gates/feature-gate-trait_upcasting.rs
new file mode 100644
index 00000000000..e4102f1cfa7
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-trait_upcasting.rs
@@ -0,0 +1,13 @@
+trait Foo {}
+
+trait Bar: Foo {}
+
+impl Foo for () {}
+
+impl Bar for () {}
+
+fn main() {
+    let bar: &dyn Bar = &();
+    let foo: &dyn Foo = bar;
+    //~^ ERROR trait upcasting coercion is experimental [E0658]
+}
diff --git a/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr b/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr
new file mode 100644
index 00000000000..bc13a5d7d7b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr
@@ -0,0 +1,12 @@
+error[E0658]: trait upcasting coercion is experimental
+  --> $DIR/feature-gate-trait_upcasting.rs:11:25
+   |
+LL |     let foo: &dyn Foo = bar;
+   |                         ^^^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-11515.rs b/src/test/ui/issues/issue-11515.rs
index a7671b9282a..2072f9c47e2 100644
--- a/src/test/ui/issues/issue-11515.rs
+++ b/src/test/ui/issues/issue-11515.rs
@@ -1,10 +1,10 @@
 #![feature(box_syntax)]
 
 struct Test {
-    func: Box<dyn FnMut() + 'static>
+    func: Box<dyn FnMut() + 'static>,
 }
 
 fn main() {
     let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
-    let test = box Test { func: closure }; //~ ERROR mismatched types
+    let test = box Test { func: closure }; //~ ERROR trait upcasting coercion is experimental [E0658]
 }
diff --git a/src/test/ui/issues/issue-11515.stderr b/src/test/ui/issues/issue-11515.stderr
index 7935615ad7e..a70e7c416bc 100644
--- a/src/test/ui/issues/issue-11515.stderr
+++ b/src/test/ui/issues/issue-11515.stderr
@@ -1,12 +1,12 @@
-error[E0308]: mismatched types
+error[E0658]: trait upcasting coercion is experimental
   --> $DIR/issue-11515.rs:9:33
    |
 LL |     let test = box Test { func: closure };
-   |                                 ^^^^^^^ expected trait `FnMut`, found trait `Fn`
+   |                                 ^^^^^^^
    |
-   = note: expected struct `Box<(dyn FnMut() + 'static)>`
-              found struct `Box<(dyn Fn() + 'static)>`
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
new file mode 100644
index 00000000000..277d9eabe4f
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
@@ -0,0 +1,13 @@
+// run-pass
+#![feature(box_syntax, trait_upcasting)]
+#![allow(incomplete_features)]
+
+struct Test {
+    func: Box<dyn FnMut() + 'static>,
+}
+
+fn main() {
+    let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
+    let mut test = box Test { func: closure };
+    (test.func)();
+}
diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs
new file mode 100644
index 00000000000..6986ad62172
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs
@@ -0,0 +1,22 @@
+// check-fail
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Bar<T> {
+    fn bar(&self, _: T) {}
+}
+
+trait Foo : Bar<i32> + Bar<u32> {
+    fn foo(&self, _: ()) {}
+}
+
+struct S;
+
+impl Bar<i32> for S {}
+impl Bar<u32> for S {}
+impl Foo for S {}
+
+fn main() {
+    let s: &dyn Foo = &S;
+    let t: &dyn Bar<_> = s; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr
new file mode 100644
index 00000000000..e9670ad7def
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/multiple-occurence-ambiguousity.rs:21:26
+   |
+LL |     let t: &dyn Bar<_> = s;
+   |            -----------   ^ expected trait `Bar`, found trait `Foo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Bar<_>`
+              found reference `&dyn Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
new file mode 100644
index 00000000000..1a0e5072843
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
@@ -0,0 +1,33 @@
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo: Bar<i32> + Bar<u32> {}
+trait Bar<T> {
+    fn bar(&self) -> Option<T> {
+        None
+    }
+}
+
+fn test_specific(x: &dyn Foo) {
+    let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
+                                //~^ ERROR non-primitive cast
+                                //~^^ ERROR the trait bound `&dyn Foo: Bar<i32>` is not satisfied
+    let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
+                                //~^ ERROR non-primitive cast
+                                //~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
+}
+
+fn test_unknown_version(x: &dyn Foo) {
+    let _ = x as &dyn Bar<_>; // Ambiguous
+                              //~^ ERROR non-primitive cast
+                              //~^^ ERROR the trait bound `&dyn Foo: Bar<_>` is not satisfied
+}
+
+fn test_infer_version(x: &dyn Foo) {
+    let a = x as &dyn Bar<_>; // FIXME: OK, eventually
+                              //~^ ERROR non-primitive cast
+                              //~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
+    let _: Option<u32> = a.bar();
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr
new file mode 100644
index 00000000000..6aaa8a4a904
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr
@@ -0,0 +1,80 @@
+error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<i32>`
+  --> $DIR/type-checking-test-1.rs:12:13
+   |
+LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
+   |             ^^^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
+   |             ^
+
+error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
+  --> $DIR/type-checking-test-1.rs:15:13
+   |
+LL |     let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
+   |             ^^^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _ = &x as &dyn Bar<u32>; // FIXME: OK, eventually
+   |             ^
+
+error[E0277]: the trait bound `&dyn Foo: Bar<i32>` is not satisfied
+  --> $DIR/type-checking-test-1.rs:12:13
+   |
+LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
+   |             ^ the trait `Bar<i32>` is not implemented for `&dyn Foo`
+   |
+   = note: required for the cast to the object type `dyn Bar<i32>`
+
+error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
+  --> $DIR/type-checking-test-1.rs:15:13
+   |
+LL |     let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
+   |             ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
+   |
+   = note: required for the cast to the object type `dyn Bar<u32>`
+
+error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
+  --> $DIR/type-checking-test-1.rs:21:13
+   |
+LL |     let _ = x as &dyn Bar<_>; // Ambiguous
+   |             ^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _ = &x as &dyn Bar<_>; // Ambiguous
+   |             ^
+
+error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied
+  --> $DIR/type-checking-test-1.rs:21:13
+   |
+LL |     let _ = x as &dyn Bar<_>; // Ambiguous
+   |             ^ the trait `Bar<_>` is not implemented for `&dyn Foo`
+   |
+   = note: required for the cast to the object type `dyn Bar<_>`
+
+error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
+  --> $DIR/type-checking-test-1.rs:27:13
+   |
+LL |     let a = x as &dyn Bar<_>; // FIXME: OK, eventually
+   |             ^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let a = &x as &dyn Bar<_>; // FIXME: OK, eventually
+   |             ^
+
+error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
+  --> $DIR/type-checking-test-1.rs:27:13
+   |
+LL |     let a = x as &dyn Bar<_>; // FIXME: OK, eventually
+   |             ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
+   |
+   = note: required for the cast to the object type `dyn Bar<u32>`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0277, E0605.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
new file mode 100644
index 00000000000..326df74211e
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
@@ -0,0 +1,34 @@
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo<T>: Bar<i32> + Bar<T> {}
+trait Bar<T> {
+    fn bar(&self) -> Option<T> {
+        None
+    }
+}
+
+fn test_specific(x: &dyn Foo<i32>) {
+    let _ = x as &dyn Bar<i32>; // OK
+}
+
+fn test_specific2(x: &dyn Foo<u32>) {
+    let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
+                                //~^ ERROR non-primitive cast
+                                //~^^ ERROR the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
+}
+
+fn test_specific3(x: &dyn Foo<i32>) {
+    let _ = x as &dyn Bar<u32>; // Error
+                                //~^ ERROR non-primitive cast
+                                //~^^ ERROR the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
+}
+
+fn test_infer_arg(x: &dyn Foo<u32>) {
+    let a = x as &dyn Bar<_>; // Ambiguous
+                              //~^ ERROR non-primitive cast
+                              //~^^ ERROR the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
+    let _ = a.bar();
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr
new file mode 100644
index 00000000000..a38f8a14604
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr
@@ -0,0 +1,61 @@
+error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<i32>`
+  --> $DIR/type-checking-test-2.rs:16:13
+   |
+LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
+   |             ^^^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
+   |             ^
+
+error[E0277]: the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
+  --> $DIR/type-checking-test-2.rs:16:13
+   |
+LL |     let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
+   |             ^ the trait `Bar<i32>` is not implemented for `&dyn Foo<u32>`
+   |
+   = note: required for the cast to the object type `dyn Bar<i32>`
+
+error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
+  --> $DIR/type-checking-test-2.rs:22:13
+   |
+LL |     let _ = x as &dyn Bar<u32>; // Error
+   |             ^^^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _ = &x as &dyn Bar<u32>; // Error
+   |             ^
+
+error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
+  --> $DIR/type-checking-test-2.rs:22:13
+   |
+LL |     let _ = x as &dyn Bar<u32>; // Error
+   |             ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>`
+   |
+   = note: required for the cast to the object type `dyn Bar<u32>`
+
+error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
+  --> $DIR/type-checking-test-2.rs:28:13
+   |
+LL |     let a = x as &dyn Bar<_>; // Ambiguous
+   |             ^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let a = &x as &dyn Bar<_>; // Ambiguous
+   |             ^
+
+error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
+  --> $DIR/type-checking-test-2.rs:28:13
+   |
+LL |     let a = x as &dyn Bar<_>; // Ambiguous
+   |             ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>`
+   |
+   = note: required for the cast to the object type `dyn Bar<_>`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0605.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs
new file mode 100644
index 00000000000..49c24e404dc
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs
@@ -0,0 +1,22 @@
+// ignore-compare-mode-nll
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo<'a>: Bar<'a> {}
+trait Bar<'a> {}
+
+fn test_correct(x: &dyn Foo<'static>) {
+    let _ = x as &dyn Bar<'static>;
+}
+
+fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
+    let _ = x as &dyn Bar<'a>; // Error
+                               //~^ ERROR mismatched types
+}
+
+fn test_wrong2<'a>(x: &dyn Foo<'a>) {
+    let _ = x as &dyn Bar<'static>; // Error
+                                    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr
new file mode 100644
index 00000000000..593ee0a3430
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+  --> $DIR/type-checking-test-3.rs:13:13
+   |
+LL |     let _ = x as &dyn Bar<'a>; // Error
+   |             ^ lifetime mismatch
+   |
+   = note: expected trait object `dyn Bar<'a>`
+              found trait object `dyn Bar<'static>`
+note: the lifetime `'a` as defined on the function body at 12:16...
+  --> $DIR/type-checking-test-3.rs:12:16
+   |
+LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
+   |                ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error[E0308]: mismatched types
+  --> $DIR/type-checking-test-3.rs:18:13
+   |
+LL |     let _ = x as &dyn Bar<'static>; // Error
+   |             ^ lifetime mismatch
+   |
+   = note: expected trait object `dyn Bar<'static>`
+              found trait object `dyn Bar<'a>`
+note: the lifetime `'a` as defined on the function body at 17:16...
+  --> $DIR/type-checking-test-3.rs:17:16
+   |
+LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) {
+   |                ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
new file mode 100644
index 00000000000..9b27fd46f7a
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
@@ -0,0 +1,32 @@
+// ignore-compare-mode-nll
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo<'a>: Bar<'a, 'a> {}
+trait Bar<'a, 'b> {
+    fn get_b(&self) -> Option<&'a u32> {
+        None
+    }
+}
+
+fn test_correct(x: &dyn Foo<'static>) {
+    let _ = x as &dyn Bar<'static, 'static>;
+}
+
+fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
+    let _ = x as &dyn Bar<'static, 'a>; // Error
+                                        //~^ ERROR mismatched types
+}
+
+fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
+    let _ = x as &dyn Bar<'a, 'static>; // Error
+                                        //~^ ERROR mismatched types
+}
+
+fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+    let y = x as &dyn Bar<'_, '_>;
+    //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+    y.get_b() // ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
new file mode 100644
index 00000000000..811e524eda7
--- /dev/null
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/type-checking-test-4.rs:17:13
+   |
+LL |     let _ = x as &dyn Bar<'static, 'a>; // Error
+   |             ^ lifetime mismatch
+   |
+   = note: expected trait object `dyn Bar<'static, 'a>`
+              found trait object `dyn Bar<'static, 'static>`
+note: the lifetime `'a` as defined on the function body at 16:16...
+  --> $DIR/type-checking-test-4.rs:16:16
+   |
+LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
+   |                ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error[E0308]: mismatched types
+  --> $DIR/type-checking-test-4.rs:22:13
+   |
+LL |     let _ = x as &dyn Bar<'a, 'static>; // Error
+   |             ^ lifetime mismatch
+   |
+   = note: expected trait object `dyn Bar<'a, 'static>`
+              found trait object `dyn Bar<'static, 'static>`
+note: the lifetime `'a` as defined on the function body at 21:16...
+  --> $DIR/type-checking-test-4.rs:21:16
+   |
+LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
+   |                ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/type-checking-test-4.rs:27:27
+   |
+LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+   |                       ------------ this data with lifetime `'a`...
+LL |     let y = x as &dyn Bar<'_, '_>;
+   |             -             ^^
+   |             |
+   |             ...is captured here...
+LL |
+LL |     y.get_b() // ERROR
+   |     --------- ...and is required to live as long as `'static` here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0759.
+For more information about an error, try `rustc --explain E0308`.