Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework opaque type region inference #116891

Merged
merged 12 commits into from
Mar 28, 2024
Prev Previous commit
Next Next commit
check RPITs for invalid args
  • Loading branch information
aliemjay committed Mar 28, 2024
commit ce91e46a1e9ad5126df1128068113d6f2d618827
12 changes: 1 addition & 11 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,27 +441,17 @@ fn check_opaque_type_parameter_valid<'tcx>(
opaque_type_key: OpaqueTypeKey<'tcx>,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
let (_parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin {
OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true),
OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false),
};

let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();

for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) if is_ty_alias => {
GenericArgKind::Lifetime(lt) => {
matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
|| (lt.is_static() && opaque_env.param_equal_static(i))
}
// FIXME(#113916): we can't currently check for unique lifetime params,
// see that issue for more. We will also have to ignore unused lifetime
// params for RPIT, but that's comparatively trivial ✨
GenericArgKind::Lifetime(_) => continue,
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/defining-use-captured-non-universal-region.rs:15:18
|
LL | fn foo<'a>() -> impl Sized + 'a {
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | let i: i32 = foo::<'_>();
| ^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0792`.
24 changes: 24 additions & 0 deletions tests/ui/impl-trait/defining-use-captured-non-universal-region.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// This was an ICE. See #110726.
// FIXME(aliemjay): outdated due to "once modulo regions" restriction.

//@ revisions: statik infer fixed
//@ [fixed] check-pass
#![allow(unconditional_recursion)]

fn foo<'a>() -> impl Sized + 'a {
#[cfg(statik)]
let i: i32 = foo::<'static>();
//[statik]~^ ERROR opaque type used twice with different lifetimes
//[statik]~| ERROR opaque type used twice with different lifetimes

#[cfg(infer)]
let i: i32 = foo::<'_>();
//[infer]~^ ERROR expected generic lifetime parameter, found `'_`

#[cfg(fixed)]
let i: i32 = foo::<'a>();

i
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
error: opaque type used twice with different lifetimes
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^ lifetime `'static` used here
...
LL | i
| - lifetime `'a` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^

error: opaque type used twice with different lifetimes
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^ lifetime `'static` used here
...
LL | i
| - lifetime `'a` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 2 previous errors

4 changes: 1 addition & 3 deletions tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
use std::fmt::Debug;

fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
//~^ ERROR cannot resolve opaque type

|x| x
//~^ ERROR concrete type differs from previous defining opaque type use
//~^ ERROR expected generic lifetime parameter, found `'_`
}

fn _b<'a>() -> impl Fn(&'a u8) -> (impl Debug + 'a) {
Expand Down
24 changes: 7 additions & 17 deletions tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
error: concrete type differs from previous defining opaque type use
--> $DIR/impl-fn-predefined-lifetimes.rs:7:9
|
LL | |x| x
| ^ expected `impl Debug + '_`, got `&u8`
|
note: previous use here
--> $DIR/impl-fn-predefined-lifetimes.rs:7:5
|
LL | |x| x
| ^^^^^

error[E0720]: cannot resolve opaque type
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/impl-fn-predefined-lifetimes.rs:5:9
|
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
| ^^^^^^^^^^^^^^^ cannot resolve opaque type
| -- this generic parameter must be used with a generic lifetime parameter
LL | |x| x
| ^

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0720`.
For more information about this error, try `rustc --explain E0792`.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ trait Foo {
fn bar<'other: 'a>() -> impl Sized + 'a {}
//~^ ERROR use of undeclared lifetime name `'a`
//~| ERROR use of undeclared lifetime name `'a`
//~| ERROR expected generic lifetime parameter, found `'static`
}

fn main() {}
13 changes: 11 additions & 2 deletions tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ help: consider introducing lifetime `'a` here
LL | trait Foo<'a> {
| ++++

error: aborting due to 2 previous errors
error[E0792]: expected generic lifetime parameter, found `'static`
--> $DIR/bad-item-bound-within-rpitit-2.rs:5:45
|
LL | fn bar<'other: 'a>() -> impl Sized + 'a {}
| ------ ^^
| |
| cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0261`.
Some errors have detailed explanations: E0261, E0792.
For more information about an error, try `rustc --explain E0261`.
1 change: 1 addition & 0 deletions tests/ui/impl-trait/rpit/early_bound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
let true = n else { loop {} };
let _ = || {
let _ = identity::<&'a ()>(test(false));
//~^ ERROR expected generic lifetime parameter, found `'_`
};
loop {}
}
Expand Down
12 changes: 11 additions & 1 deletion tests/ui/impl-trait/rpit/early_bound.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/early_bound.rs:7:17
|
LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a {
| -- this generic parameter must be used with a generic lifetime parameter
...
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: concrete type differs from previous defining opaque type use
--> $DIR/early_bound.rs:3:29
|
Expand All @@ -10,5 +19,6 @@ note: previous use here
LL | let _ = identity::<&'a ()>(test(false));
| ^^^^^^^^^^^

error: aborting due to 1 previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0792`.
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// issue: #111935
// FIXME(aliemjay): outdated due to "once modulo regions" restriction.
// FIXME(aliemjay): mod `infer` should fail.

#![allow(unconditional_recursion)]

Expand All @@ -22,6 +21,7 @@ mod infer {
// invalid defining use: Opaque<'_> := ()
fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
let _: () = foo(Lt::<'_>::None);
//~^ ERROR expected generic lifetime parameter, found `'_`
}
}

Expand Down
15 changes: 12 additions & 3 deletions tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: opaque type used twice with different lifetimes
--> $DIR/non-defining-use-lifetimes.rs:15:16
--> $DIR/non-defining-use-lifetimes.rs:14:16
|
LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
| ______________________________________________-
Expand All @@ -10,11 +10,19 @@ LL | | }
| |_____- lifetime `'a` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/non-defining-use-lifetimes.rs:15:16
--> $DIR/non-defining-use-lifetimes.rs:14:16
|
LL | let _: () = foo(Lt::<'static>::None);
| ^^

error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/non-defining-use-lifetimes.rs:23:16
|
LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
| -- this generic parameter must be used with a generic lifetime parameter
LL | let _: () = foo(Lt::<'_>::None);
| ^^

error: opaque type used twice with different lifetimes
--> $DIR/non-defining-use-lifetimes.rs:33:16
|
Expand All @@ -32,5 +40,6 @@ note: if all non-lifetime generic parameters are the same, but the lifetime para
LL | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None);
| ^^

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0792`.
1 change: 1 addition & 0 deletions tests/ui/type-alias-impl-trait/hkl_forbidden4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type FutNothing<'a> = impl 'a + Future<Output = ()>;
async fn operation(_: &mut ()) -> () {
//~^ ERROR: concrete type differs from previous
call(operation).await
//~^ ERROR: expected generic lifetime parameter, found `'any`
}

async fn call<F>(_f: F)
Expand Down
27 changes: 18 additions & 9 deletions tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,17 @@ LL | type FutNothing<'a> = impl 'a + Future<Output = ()>;
|
= note: `FutNothing` must be used in combination with a concrete type within the same module

error: concrete type differs from previous defining opaque type use
--> $DIR/hkl_forbidden4.rs:13:1
|
LL | async fn operation(_: &mut ()) -> () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body of operation()}`
|
note: previous use here
error[E0792]: expected generic lifetime parameter, found `'any`
--> $DIR/hkl_forbidden4.rs:15:5
|
LL | async fn operation(_: &mut ()) -> () {
| - this generic parameter must be used with a generic lifetime parameter
LL |
LL | call(operation).await
| ^^^^^^^^^^^^^^^

error[E0792]: expected generic lifetime parameter, found `'any`
--> $DIR/hkl_forbidden4.rs:21:1
--> $DIR/hkl_forbidden4.rs:22:1
|
LL | type FutNothing<'a> = impl 'a + Future<Output = ()>;
| -- this generic parameter must be used with a generic lifetime parameter
Expand All @@ -29,6 +26,18 @@ LL | |
LL | | }
| |_^

error: aborting due to 3 previous errors
error: concrete type differs from previous defining opaque type use
--> $DIR/hkl_forbidden4.rs:13:1
|
LL | async fn operation(_: &mut ()) -> () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body of operation()}`
|
note: previous use here
--> $DIR/hkl_forbidden4.rs:15:5
|
LL | call(operation).await
| ^^^^^^^^^^^^^^^

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0792`.