]> git.lizzy.rs Git - rust.git/commitdiff
Check opaque types satisfy their bounds
authorMatthew Jasper <mjjasper1@gmail.com>
Sun, 28 Jun 2020 15:46:02 +0000 (16:46 +0100)
committerMatthew Jasper <mjjasper1@gmail.com>
Tue, 6 Oct 2020 10:19:30 +0000 (11:19 +0100)
22 files changed:
compiler/rustc_trait_selection/src/opaque_types.rs
compiler/rustc_typeck/src/check/check.rs
src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
src/test/ui/async-await/async-error-span.stderr
src/test/ui/async-await/issue-64130-4-async-move.stderr
src/test/ui/async-await/issue-70818.stderr
src/test/ui/generator/type-mismatch-signature-deduction.stderr
src/test/ui/impl-trait/bound-normalization-fail.stderr
src/test/ui/impl-trait/issue-55872-1.stderr
src/test/ui/issues-71798.stderr
src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
src/test/ui/never_type/feature-gate-never_type_fallback.stderr
src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/bounds-are-checked.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs
src/test/ui/type-alias-impl-trait/issue-60371.stderr
src/test/ui/type-alias-impl-trait/issue-63279.stderr
src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs

index 1babfb8508ed8f65a774fd135ff372772f3bf4ea..0621d9bf09e138f9351cf77e47e23b7793cb239e 100644 (file)
@@ -1170,7 +1170,8 @@ fn fold_opaque_ty(
             // This also instantiates nested instances of `impl Trait`.
             let predicate = self.instantiate_opaque_types_in_map(&predicate);
 
-            let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType);
+            let cause =
+                traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
 
             // Require that the predicate holds for the concrete type.
             debug!("instantiate_opaque_types: predicate={:?}", predicate);
index 2df9007195fae18baf13ead9a2e2d326d225f7b9..f5e6ff07b88b7bdf2aa64040beb59f8f91aa1441 100644 (file)
@@ -387,7 +387,10 @@ pub(super) fn check_opaque<'tcx>(
 ) {
     check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
     tcx.ensure().type_of(def_id);
-    check_opaque_for_cycles(tcx, def_id, substs, span, origin);
+    if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
+        return;
+    }
+    check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
 }
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -504,7 +507,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
     substs: SubstsRef<'tcx>,
     span: Span,
     origin: &hir::OpaqueTyOrigin,
-) {
+) -> Result<(), ErrorReported> {
     if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
     {
         match origin {
@@ -514,7 +517,68 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
             }
             _ => opaque_type_cycle_error(tcx, def_id, span),
         }
+        Err(ErrorReported)
+    } else {
+        Ok(())
+    }
+}
+
+/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
+fn check_opaque_meets_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    substs: SubstsRef<'tcx>,
+    span: Span,
+    origin: &hir::OpaqueTyOrigin,
+) {
+    match origin {
+        // Checked when type checking the function containing them.
+        hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return,
+        // Can have different predicates to their defining use
+        hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => {}
     }
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let param_env = tcx.param_env(def_id);
+
+    tcx.infer_ctxt().enter(move |infcx| {
+        let inh = Inherited::new(infcx, def_id);
+        let infcx = &inh.infcx;
+        let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+
+        let misc_cause = traits::ObligationCause::misc(span, hir_id);
+
+        let (_, opaque_type_map) = inh.register_infer_ok_obligations(
+            infcx.instantiate_opaque_types(def_id.to_def_id(), hir_id, param_env, &opaque_ty, span),
+        );
+
+        for (def_id, opaque_defn) in opaque_type_map {
+            match infcx
+                .at(&misc_cause, param_env)
+                .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
+            {
+                Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
+                Err(ty_err) => tcx.sess.delay_span_bug(
+                    opaque_defn.definition_span,
+                    &format!(
+                        "could not unify `{}` with revealed type:\n{}",
+                        opaque_defn.concrete_ty, ty_err,
+                    ),
+                ),
+            }
+        }
+
+        // Check that all obligations are satisfied by the implementation's
+        // version.
+        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+            infcx.report_fulfillment_errors(errors, None, false);
+        }
+
+        // Finally, resolve all regions. This catches wily misuses of
+        // lifetime parameters.
+        let fcx = FnCtxt::new(&inh, param_env, hir_id);
+        fcx.regionck_item(hir_id, span, &[]);
+    });
 }
 
 pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
index 566e390a31e4820cd68b60192ba1d320f69cdad9..b0e9e33a6c38ecffeda0cbef786f32659c24878f 100644 (file)
@@ -9,7 +9,6 @@ LL | fn baz() -> impl Bar<Item = i32> {
    |
    = note: expected associated type `<impl Bar as Foo>::Item`
                          found type `i32`
-   = note: the return type of a function must have a statically known size
 help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
    |
 LL | fn bar() -> impl Bar<Item = i32> {
index d808a5939bbe79769a5bd4765359c2f8fd027cef..8cd0e40c8cf841131514590cbfaa6ad5b079418b 100644 (file)
@@ -3,9 +3,6 @@ error[E0277]: `()` is not a future
    |
 LL | fn get_future() -> impl Future<Output = ()> {
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
-LL |
-LL |     panic!()
-   |     -------- this returned value is of type `!`
    |
    = help: the trait `Future` is not implemented for `()`
    = note: the return type of a function must have a statically known size
index 440ea0a38e6b902c440ce7ce2a32d24d3da42a04..f5d023ab781ff761cb7bce4212ad767652928cb2 100644 (file)
@@ -30,7 +30,6 @@ help: consider moving this into a `let` binding to create a shorter lived borrow
    |
 LL |         match client.status() {
    |               ^^^^^^^^^^^^^^^
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
index 364194bea100e914c2d285a3a68a22976699d1f2..20ee22e448c91970672efbb2780dd4423b796a76 100644 (file)
@@ -12,7 +12,6 @@ note: captured value is not `Send`
    |
 LL |     async { (ty, ty1) }
    |                  ^^^ has type `U` which is not `Send`
-   = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `U`
    |
 LL | fn foo<T: Send, U: Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
index 260fbb2ec7e6af34251716efebcbde13d86dae74..8f6f87f78de707e5d1d998b06d20f1f8085262c0 100644 (file)
@@ -15,7 +15,6 @@ LL | fn foo() -> impl Generator<Return = i32> {
    |
    = note: expected enum `std::result::Result<{integer}, _>`
               found type `i32`
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to 2 previous errors
 
index 03aba10cc79b4a28468fb2fede535ac2102a3953..a7d06c71663de259f4d492da884c8df32a98f423 100644 (file)
@@ -15,7 +15,6 @@ LL |     fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
    |
    = note:         expected type `()`
            found associated type `<T as impl_trait::Trait>::Assoc`
-   = note: the return type of a function must have a statically known size
 help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
    |
 LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
@@ -35,7 +34,6 @@ LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
    |
    = note:         expected type `()`
            found associated type `<T as lifetimes::Trait<'static>>::Assoc`
-   = note: the return type of a function must have a statically known size
 help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
    |
 LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
index db49d988bb8eb81ae62e0a86172ae23c04e0b871..64c536cf1fe30b5513c20a22027d00a22453744c 100644 (file)
@@ -14,7 +14,6 @@ LL |     type E = impl Copy;
    |              ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
    |
    = note: required because it appears within the type `(S, T)`
-   = note: the return type of a function must have a statically known size
 help: consider further restricting this bound
    |
 LL | impl<S: Default + Copy> Bar for S {
@@ -27,7 +26,6 @@ LL |     type E = impl Copy;
    |              ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
    |
    = note: required because it appears within the type `(S, T)`
-   = note: the return type of a function must have a statically known size
 help: consider further restricting this bound
    |
 LL |     fn foo<T: Default + Copy>() -> Self::E {
index 867f8f0496c033a99b2cbab8ba61ce2860a06563..835d479f28f198737d9a3502b0f86ead8e53b966 100644 (file)
@@ -9,8 +9,6 @@ error[E0277]: `u32` is not a future
    |
 LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
-LL |     *x
-   |     -- this returned value is of type `u32`
    |
    = help: the trait `Future` is not implemented for `u32`
    = note: the return type of a function must have a statically known size
index e43fb6d0edfb9e730892d6cb0a3eef0fb090b8d2..c3d597bec2e406e7a86e2099631664f756430972 100644 (file)
@@ -3,11 +3,6 @@ error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisf
    |
 LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>`
-LL |
-LL |     Ok(())
-   |     ------ this returned value is of type `std::result::Result<(), _>`
-   |
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
index c652faafad4613444163815c748f2c564770b02e..670f76867ce45122b29e6ebba4a3c628318c9507 100644 (file)
@@ -3,11 +3,6 @@ error[E0277]: the trait bound `(): T` is not satisfied
    |
 LL | fn should_ret_unit() -> impl T {
    |                         ^^^^^^ the trait `T` is not implemented for `()`
-LL |
-LL |     panic!()
-   |     -------- this returned value is of type `!`
-   |
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
index cc3a2b9419caf00b534f84325439ed7d00af08b9..d826222a06ae5d95fbd5838bc2b3fac95821e218 100644 (file)
@@ -5,8 +5,6 @@ LL | fn foo() -> impl Bar {
    |             ^^^^^^^^ the trait `Bar` is not implemented for `()`
 LL |     5;
    |      - consider removing this semicolon
-   |
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs
new file mode 100644 (file)
index 0000000..5566f40
--- /dev/null
@@ -0,0 +1,19 @@
+// Make sure that we check that impl trait types implement the traits that they
+// claim to.
+
+#![feature(type_alias_impl_trait)]
+
+type X<T> = impl Clone;
+//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
+
+fn f<T: Clone>(t: T) -> X<T> {
+    t
+}
+
+fn g<T>(o : Option<X<T>>) -> Option<X<T>> {
+    o.clone()
+}
+
+fn main() {
+    g(None::<X<&mut ()>>);
+}
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
new file mode 100644 (file)
index 0000000..e201300
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
+  --> $DIR/bounds-are-checked-2.rs:6:13
+   |
+LL | type X<T> = impl Clone;
+   |             ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | type X<T: std::clone::Clone> = impl Clone;
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs b/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
new file mode 100644 (file)
index 0000000..759bf4f
--- /dev/null
@@ -0,0 +1,25 @@
+// Make sure that we check that impl trait types implement the traits that they
+// claim to.
+
+#![feature(type_alias_impl_trait)]
+
+type X<'a> = impl Into<&'static str> + From<&'a str>;
+//~^ ERROR mismatched types
+
+fn f<'a: 'static>(t: &'a str) -> X<'a> {
+    //~^ WARNING unnecessary lifetime parameter
+    t
+}
+
+fn extend_lt<'a>(o: &'a str) -> &'static str {
+    X::<'_>::from(o).into()
+}
+
+fn main() {
+    let r =
+    {
+        let s = "abcdef".to_string();
+        extend_lt(&s)
+    };
+    println!("{}", r);
+}
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
new file mode 100644 (file)
index 0000000..42468b9
--- /dev/null
@@ -0,0 +1,26 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/bounds-are-checked.rs:9:6
+   |
+LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
+   |      ^^^^^^^^^^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+error[E0308]: mismatched types
+  --> $DIR/bounds-are-checked.rs:6:14
+   |
+LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected type `std::convert::From<&'a str>`
+              found type `std::convert::From<&'static str>`
+note: the lifetime `'a` as defined on the item at 6:8...
+  --> $DIR/bounds-are-checked.rs:6:8
+   |
+LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
+   |        ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
index 898dab1b0b9602808b58671eb45540e2e7b3be66..c17d595dbb3ad23e07b33f73bad8e6b4dee960d8 100644 (file)
@@ -1,11 +1,11 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![feature(type_alias_impl_trait)]
 
 use std::fmt::Debug;
 
 fn main() {}
 
-type Two<T, U> = impl Debug;
+type Two<T: Debug, U> = impl Debug;
 
 fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
     (t, 4u32)
index 712a6539f0153720b887aaa6452e784221185b0d..feebf81eef2a7f87274fe42a3b7952fa261737f4 100644 (file)
@@ -1,11 +1,11 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![feature(type_alias_impl_trait)]
 
 use std::fmt::Debug;
 
 fn main() {}
 
-type Two<A, B> = impl Debug;
+type Two<A: Debug, B> = impl Debug;
 
 fn two<T: Debug + Copy, U>(t: T, u: U) -> Two<T, U> {
     (t, t)
index bf2d612fcdb411511500d8dc3b6494582a040522..905248fb33755992d0ec2637edc0f48a0949304c 100644 (file)
@@ -15,7 +15,6 @@ LL |     type Item = impl Bug;
    |
    = help: the following implementations were found:
              <&() as Bug>
-   = note: the return type of a function must have a statically known size
 
 error: could not find defining uses
   --> $DIR/issue-60371.rs:8:17
index 9ad181b3684c6dd1382aeeccfd747b3e9a779e6b..8615b3f741bf53ea43ddb27cebcfe38b5b8f4b0d 100644 (file)
@@ -6,7 +6,6 @@ LL | type Closure = impl FnOnce();
    |
    = note: expected opaque type `impl FnOnce<()>`
                 found unit type `()`
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
index 209134acf01f9723d50d9421bdf0caeb0074c306..80192d19af98b5cd9d63f5f89b664570a558dc1d 100644 (file)
@@ -70,14 +70,14 @@ fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
 }
 
 trait Trait {}
-type GenericBound<'a, T: Trait> = impl Sized + 'a;
+type GenericBound<'a, T: Trait + 'a> = impl Sized + 'a;
 
 fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
     t
 }
 
 mod pass_through {
-    pub type Passthrough<T> = impl Sized + 'static;
+    pub type Passthrough<T: 'static> = impl Sized + 'static;
 
     fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
         t