about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2023-07-21 12:27:41 +0200
committerlcnr <rust@lcnr.de>2023-08-14 15:25:20 +0200
commit95fddbc501ba8029eba3b1ab36ed86d2677bfd17 (patch)
treeaa63774a757b86bfa7a5995cd108f716f0680bb2
parent3071e0aef6dfd0a150c3fb1da0abad4ec86ca0aa (diff)
downloadrust-95fddbc501ba8029eba3b1ab36ed86d2677bfd17.tar.gz
rust-95fddbc501ba8029eba3b1ab36ed86d2677bfd17.zip
check for non-defining uses of RPIT
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs44
-rw-r--r--tests/ui/impl-trait/issue-99073-2.rs1
-rw-r--r--tests/ui/impl-trait/issue-99073-2.stderr18
-rw-r--r--tests/ui/impl-trait/issue-99073.rs1
-rw-r--r--tests/ui/impl-trait/issue-99073.stderr21
-rw-r--r--tests/ui/impl-trait/rpit/equal-lifetime-params-ok.rs19
-rw-r--r--tests/ui/impl-trait/rpit/non-defining-use.rs14
-rw-r--r--tests/ui/impl-trait/rpit/non-defining-use.stderr31
8 files changed, 112 insertions, 37 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 68dddd65acb..ff3883240e2 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -371,39 +371,29 @@ fn check_opaque_type_parameter_valid(
     span: Span,
 ) -> Result<(), ErrorGuaranteed> {
     let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
-    match opaque_ty_hir.expect_opaque_ty().origin {
-        // No need to check return position impl trait (RPIT)
-        // because for type and const parameters they are correct
-        // by construction: we convert
-        //
-        // fn foo<P0..Pn>() -> impl Trait
-        //
-        // into
-        //
-        // type Foo<P0...Pn>
-        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
-        //
-        // For lifetime parameters we convert
-        //
-        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
-        //
-        // into
-        //
-        // type foo::<'p0..'pn>::Foo<'q0..'qm>
-        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
-        //
-        // which would error here on all of the `'static` args.
-        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
-        // Check these
-        OpaqueTyOrigin::TyAlias { .. } => {}
-    }
+    let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin {
+        OpaqueTyOrigin::TyAlias { .. } => true,
+        OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false,
+    };
+
     let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
     let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
     for (i, arg) in opaque_type_key.args.iter().enumerate() {
+        if let Err(guar) = arg.error_reported() {
+            return Err(guar);
+        }
+
         let arg_is_param = match arg.unpack() {
             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
             GenericArgKind::Lifetime(lt) => {
-                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+                if is_ty_alias {
+                    matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+                } else {
+                    // FIXME(#113916): we can't currently check for unique lifetime params,
+                    // see that issue for more. We will also have to ignore bivariant lifetime
+                    // params for RPIT, but that's comparatively trivial ✨
+                    continue;
+                }
             }
             GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
         };
diff --git a/tests/ui/impl-trait/issue-99073-2.rs b/tests/ui/impl-trait/issue-99073-2.rs
index 14ac688806b..37ea211bec3 100644
--- a/tests/ui/impl-trait/issue-99073-2.rs
+++ b/tests/ui/impl-trait/issue-99073-2.rs
@@ -8,6 +8,7 @@ fn test<T: Display>(t: T, recurse: bool) -> impl Display {
     let f = || {
         let i: u32 = test::<i32>(-1, false);
         //~^ ERROR concrete type differs from previous defining opaque type use
+        //~| ERROR expected generic type parameter, found `i32`
         println!("{i}");
     };
     if recurse {
diff --git a/tests/ui/impl-trait/issue-99073-2.stderr b/tests/ui/impl-trait/issue-99073-2.stderr
index 913bc8f5674..06b2b84569f 100644
--- a/tests/ui/impl-trait/issue-99073-2.stderr
+++ b/tests/ui/impl-trait/issue-99073-2.stderr
@@ -1,3 +1,12 @@
+error[E0792]: expected generic type parameter, found `i32`
+  --> $DIR/issue-99073-2.rs:9:22
+   |
+LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
+   |         - this generic parameter must be used with a generic type parameter
+LL |     let f = || {
+LL |         let i: u32 = test::<i32>(-1, false);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^
+
 error: concrete type differs from previous defining opaque type use
   --> $DIR/issue-99073-2.rs:9:22
    |
@@ -5,10 +14,11 @@ LL |         let i: u32 = test::<i32>(-1, false);
    |                      ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32`
    |
 note: previous use here
-  --> $DIR/issue-99073-2.rs:16:5
+  --> $DIR/issue-99073-2.rs:7:45
    |
-LL |     t
-   |     ^
+LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
+   |                                             ^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/impl-trait/issue-99073.rs b/tests/ui/impl-trait/issue-99073.rs
index 7798e247df0..b4ef3e66f96 100644
--- a/tests/ui/impl-trait/issue-99073.rs
+++ b/tests/ui/impl-trait/issue-99073.rs
@@ -5,4 +5,5 @@ fn main() {
 fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
   move || f(fix(&f))
   //~^ ERROR concrete type differs from previous defining opaque type use
+  //~| ERROR expected generic type parameter, found `&F`
 }
diff --git a/tests/ui/impl-trait/issue-99073.stderr b/tests/ui/impl-trait/issue-99073.stderr
index 54636795349..a8400080e5a 100644
--- a/tests/ui/impl-trait/issue-99073.stderr
+++ b/tests/ui/impl-trait/issue-99073.stderr
@@ -1,14 +1,23 @@
-error: concrete type differs from previous defining opaque type use
+error[E0792]: expected generic type parameter, found `&F`
   --> $DIR/issue-99073.rs:6:11
    |
+LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
+   |        - this generic parameter must be used with a generic type parameter
+LL |   move || f(fix(&f))
+   |           ^^^^^^^^^^
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/issue-99073.rs:6:13
+   |
 LL |   move || f(fix(&f))
-   |           ^^^^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G`
+   |             ^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G`
    |
 note: previous use here
-  --> $DIR/issue-99073.rs:6:3
+  --> $DIR/issue-99073.rs:5:36
    |
-LL |   move || f(fix(&f))
-   |   ^^^^^^^^^^^^^^^^^^
+LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
+   |                                    ^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/impl-trait/rpit/equal-lifetime-params-ok.rs b/tests/ui/impl-trait/rpit/equal-lifetime-params-ok.rs
new file mode 100644
index 00000000000..6207381c745
--- /dev/null
+++ b/tests/ui/impl-trait/rpit/equal-lifetime-params-ok.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+// related to #113916, check that using RPITs in functions with lifetime params
+// which are constrained to be equal compiles.
+
+trait Trait<'a, 'b> {}
+impl Trait<'_, '_> for () {}
+fn pass<'a: 'b, 'b: 'a>() -> impl Trait<'a, 'b> {
+    (|| {})()
+}
+
+struct Foo<'a>(&'a ());
+impl<'a> Foo<'a> {
+    fn bar<'b: 'a>(&'b self) -> impl Trait<'a, 'b> {
+        let _: &'a &'b &'a ();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/rpit/non-defining-use.rs b/tests/ui/impl-trait/rpit/non-defining-use.rs
new file mode 100644
index 00000000000..255a8929a87
--- /dev/null
+++ b/tests/ui/impl-trait/rpit/non-defining-use.rs
@@ -0,0 +1,14 @@
+// Regression test for #111935 that non-defining uses of RPIT result in errors
+#![allow(unconditional_recursion)]
+fn foo<T>() -> impl Sized {
+    let _: () = foo::<u8>(); //~ ERROR expected generic type parameter, found `u8`
+}
+
+fn bar<T>(val: T) -> impl Sized {
+    let _: u8 = bar(0u8);
+    //~^ ERROR concrete type differs from previous defining opaque type use
+    //~| ERROR expected generic type parameter, found `u8`
+    val
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/rpit/non-defining-use.stderr b/tests/ui/impl-trait/rpit/non-defining-use.stderr
new file mode 100644
index 00000000000..19987d47672
--- /dev/null
+++ b/tests/ui/impl-trait/rpit/non-defining-use.stderr
@@ -0,0 +1,31 @@
+error[E0792]: expected generic type parameter, found `u8`
+  --> $DIR/non-defining-use.rs:4:12
+   |
+LL | fn foo<T>() -> impl Sized {
+   |        - this generic parameter must be used with a generic type parameter
+LL |     let _: () = foo::<u8>();
+   |            ^^
+
+error[E0792]: expected generic type parameter, found `u8`
+  --> $DIR/non-defining-use.rs:8:12
+   |
+LL | fn bar<T>(val: T) -> impl Sized {
+   |        - this generic parameter must be used with a generic type parameter
+LL |     let _: u8 = bar(0u8);
+   |            ^^
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/non-defining-use.rs:8:17
+   |
+LL |     let _: u8 = bar(0u8);
+   |                 ^^^^^^^^ expected `T`, got `u8`
+   |
+note: previous use here
+  --> $DIR/non-defining-use.rs:7:22
+   |
+LL | fn bar<T>(val: T) -> impl Sized {
+   |                      ^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0792`.