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() -> impl Trait - // - // into - // - // type Foo - // fn foo() -> Foo. - // - // For lifetime parameters we convert - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo() -> 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: T, recurse: bool) -> impl Display { let f = || { let i: u32 = test::(-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: T, recurse: bool) -> impl Display { + | - this generic parameter must be used with a generic type parameter +LL | let f = || { +LL | let i: u32 = test::(-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::(-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: 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: 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: F) -> impl Fn() { + | - this generic parameter must be used with a generic type parameter LL | move || f(fix(&f)) - | ^^^^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G` + | ^^^^^^^^^^ + +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` | 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: 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() -> impl Sized { + let _: () = foo::(); //~ ERROR expected generic type parameter, found `u8` +} + +fn bar(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() -> impl Sized { + | - this generic parameter must be used with a generic type parameter +LL | let _: () = foo::(); + | ^^ + +error[E0792]: expected generic type parameter, found `u8` + --> $DIR/non-defining-use.rs:8:12 + | +LL | fn bar(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(val: T) -> impl Sized { + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0792`.