diff options
| author | lcnr <rust@lcnr.de> | 2023-07-21 12:27:41 +0200 |
|---|---|---|
| committer | lcnr <rust@lcnr.de> | 2023-08-14 15:25:20 +0200 |
| commit | 95fddbc501ba8029eba3b1ab36ed86d2677bfd17 (patch) | |
| tree | aa63774a757b86bfa7a5995cd108f716f0680bb2 | |
| parent | 3071e0aef6dfd0a150c3fb1da0abad4ec86ca0aa (diff) | |
| download | rust-95fddbc501ba8029eba3b1ab36ed86d2677bfd17.tar.gz rust-95fddbc501ba8029eba3b1ab36ed86d2677bfd17.zip | |
check for non-defining uses of RPIT
| -rw-r--r-- | compiler/rustc_borrowck/src/region_infer/opaque_types.rs | 44 | ||||
| -rw-r--r-- | tests/ui/impl-trait/issue-99073-2.rs | 1 | ||||
| -rw-r--r-- | tests/ui/impl-trait/issue-99073-2.stderr | 18 | ||||
| -rw-r--r-- | tests/ui/impl-trait/issue-99073.rs | 1 | ||||
| -rw-r--r-- | tests/ui/impl-trait/issue-99073.stderr | 21 | ||||
| -rw-r--r-- | tests/ui/impl-trait/rpit/equal-lifetime-params-ok.rs | 19 | ||||
| -rw-r--r-- | tests/ui/impl-trait/rpit/non-defining-use.rs | 14 | ||||
| -rw-r--r-- | tests/ui/impl-trait/rpit/non-defining-use.stderr | 31 |
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`. |
