check for non-defining uses of RPIT

This commit is contained in:
lcnr 2023-07-21 12:27:41 +02:00
parent 3071e0aef6
commit 95fddbc501
8 changed files with 112 additions and 37 deletions

View File

@ -371,39 +371,29 @@ fn check_opaque_type_parameter_valid(
span: Span, span: Span,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
match opaque_ty_hir.expect_opaque_ty().origin { let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin {
// No need to check return position impl trait (RPIT) OpaqueTyOrigin::TyAlias { .. } => true,
// because for type and const parameters they are correct OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false,
// 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 opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
for (i, arg) in opaque_type_key.args.iter().enumerate() { 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() { let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) => { 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(_)), GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
}; };

View File

@ -8,6 +8,7 @@ fn test<T: Display>(t: T, recurse: bool) -> impl Display {
let f = || { let f = || {
let i: u32 = test::<i32>(-1, false); let i: u32 = test::<i32>(-1, false);
//~^ ERROR concrete type differs from previous defining opaque type use //~^ ERROR concrete type differs from previous defining opaque type use
//~| ERROR expected generic type parameter, found `i32`
println!("{i}"); println!("{i}");
}; };
if recurse { if recurse {

View File

@ -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 error: concrete type differs from previous defining opaque type use
--> $DIR/issue-99073-2.rs:9:22 --> $DIR/issue-99073-2.rs:9:22
| |
@ -5,10 +14,11 @@ LL | let i: u32 = test::<i32>(-1, false);
| ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32` | ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32`
| |
note: previous use here 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`.

View File

@ -5,4 +5,5 @@ fn main() {
fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() { fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
move || f(fix(&f)) move || f(fix(&f))
//~^ ERROR concrete type differs from previous defining opaque type use //~^ ERROR concrete type differs from previous defining opaque type use
//~| ERROR expected generic type parameter, found `&F`
} }

View File

@ -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 --> $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)) 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 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`.

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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`.