Skip to content

Commit 95fddbc

Browse files
committed
check for non-defining uses of RPIT
1 parent 3071e0a commit 95fddbc

File tree

8 files changed

+112
-37
lines changed

8 files changed

+112
-37
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+17-27
Original file line numberDiff line numberDiff line change
@@ -371,39 +371,29 @@ fn check_opaque_type_parameter_valid(
371371
span: Span,
372372
) -> Result<(), ErrorGuaranteed> {
373373
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
374-
match opaque_ty_hir.expect_opaque_ty().origin {
375-
// No need to check return position impl trait (RPIT)
376-
// because for type and const parameters they are correct
377-
// by construction: we convert
378-
//
379-
// fn foo<P0..Pn>() -> impl Trait
380-
//
381-
// into
382-
//
383-
// type Foo<P0...Pn>
384-
// fn foo<P0..Pn>() -> Foo<P0...Pn>.
385-
//
386-
// For lifetime parameters we convert
387-
//
388-
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
389-
//
390-
// into
391-
//
392-
// type foo::<'p0..'pn>::Foo<'q0..'qm>
393-
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
394-
//
395-
// which would error here on all of the `'static` args.
396-
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
397-
// Check these
398-
OpaqueTyOrigin::TyAlias { .. } => {}
399-
}
374+
let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin {
375+
OpaqueTyOrigin::TyAlias { .. } => true,
376+
OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false,
377+
};
378+
400379
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
401380
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
402381
for (i, arg) in opaque_type_key.args.iter().enumerate() {
382+
if let Err(guar) = arg.error_reported() {
383+
return Err(guar);
384+
}
385+
403386
let arg_is_param = match arg.unpack() {
404387
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
405388
GenericArgKind::Lifetime(lt) => {
406-
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
389+
if is_ty_alias {
390+
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
391+
} else {
392+
// FIXME(#113916): we can't currently check for unique lifetime params,
393+
// see that issue for more. We will also have to ignore bivariant lifetime
394+
// params for RPIT, but that's comparatively trivial ✨
395+
continue;
396+
}
407397
}
408398
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
409399
};

tests/ui/impl-trait/issue-99073-2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ fn test<T: Display>(t: T, recurse: bool) -> impl Display {
88
let f = || {
99
let i: u32 = test::<i32>(-1, false);
1010
//~^ ERROR concrete type differs from previous defining opaque type use
11+
//~| ERROR expected generic type parameter, found `i32`
1112
println!("{i}");
1213
};
1314
if recurse {
+14-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1+
error[E0792]: expected generic type parameter, found `i32`
2+
--> $DIR/issue-99073-2.rs:9:22
3+
|
4+
LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
5+
| - this generic parameter must be used with a generic type parameter
6+
LL | let f = || {
7+
LL | let i: u32 = test::<i32>(-1, false);
8+
| ^^^^^^^^^^^^^^^^^^^^^^
9+
110
error: concrete type differs from previous defining opaque type use
211
--> $DIR/issue-99073-2.rs:9:22
312
|
413
LL | let i: u32 = test::<i32>(-1, false);
514
| ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32`
615
|
716
note: previous use here
8-
--> $DIR/issue-99073-2.rs:16:5
17+
--> $DIR/issue-99073-2.rs:7:45
918
|
10-
LL | t
11-
| ^
19+
LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
20+
| ^^^^^^^^^^^^
1221

13-
error: aborting due to previous error
22+
error: aborting due to 2 previous errors
1423

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

tests/ui/impl-trait/issue-99073.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ fn main() {
55
fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
66
move || f(fix(&f))
77
//~^ ERROR concrete type differs from previous defining opaque type use
8+
//~| ERROR expected generic type parameter, found `&F`
89
}
+15-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
error: concrete type differs from previous defining opaque type use
1+
error[E0792]: expected generic type parameter, found `&F`
22
--> $DIR/issue-99073.rs:6:11
33
|
4+
LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
5+
| - this generic parameter must be used with a generic type parameter
6+
LL | move || f(fix(&f))
7+
| ^^^^^^^^^^
8+
9+
error: concrete type differs from previous defining opaque type use
10+
--> $DIR/issue-99073.rs:6:13
11+
|
412
LL | move || f(fix(&f))
5-
| ^^^^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G`
13+
| ^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G`
614
|
715
note: previous use here
8-
--> $DIR/issue-99073.rs:6:3
16+
--> $DIR/issue-99073.rs:5:36
917
|
10-
LL | move || f(fix(&f))
11-
| ^^^^^^^^^^^^^^^^^^
18+
LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
19+
| ^^^^^^^^^
1220

13-
error: aborting due to previous error
21+
error: aborting due to 2 previous errors
1422

23+
For more information about this error, try `rustc --explain E0792`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// check-pass
2+
3+
// related to #113916, check that using RPITs in functions with lifetime params
4+
// which are constrained to be equal compiles.
5+
6+
trait Trait<'a, 'b> {}
7+
impl Trait<'_, '_> for () {}
8+
fn pass<'a: 'b, 'b: 'a>() -> impl Trait<'a, 'b> {
9+
(|| {})()
10+
}
11+
12+
struct Foo<'a>(&'a ());
13+
impl<'a> Foo<'a> {
14+
fn bar<'b: 'a>(&'b self) -> impl Trait<'a, 'b> {
15+
let _: &'a &'b &'a ();
16+
}
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Regression test for #111935 that non-defining uses of RPIT result in errors
2+
#![allow(unconditional_recursion)]
3+
fn foo<T>() -> impl Sized {
4+
let _: () = foo::<u8>(); //~ ERROR expected generic type parameter, found `u8`
5+
}
6+
7+
fn bar<T>(val: T) -> impl Sized {
8+
let _: u8 = bar(0u8);
9+
//~^ ERROR concrete type differs from previous defining opaque type use
10+
//~| ERROR expected generic type parameter, found `u8`
11+
val
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0792]: expected generic type parameter, found `u8`
2+
--> $DIR/non-defining-use.rs:4:12
3+
|
4+
LL | fn foo<T>() -> impl Sized {
5+
| - this generic parameter must be used with a generic type parameter
6+
LL | let _: () = foo::<u8>();
7+
| ^^
8+
9+
error[E0792]: expected generic type parameter, found `u8`
10+
--> $DIR/non-defining-use.rs:8:12
11+
|
12+
LL | fn bar<T>(val: T) -> impl Sized {
13+
| - this generic parameter must be used with a generic type parameter
14+
LL | let _: u8 = bar(0u8);
15+
| ^^
16+
17+
error: concrete type differs from previous defining opaque type use
18+
--> $DIR/non-defining-use.rs:8:17
19+
|
20+
LL | let _: u8 = bar(0u8);
21+
| ^^^^^^^^ expected `T`, got `u8`
22+
|
23+
note: previous use here
24+
--> $DIR/non-defining-use.rs:7:22
25+
|
26+
LL | fn bar<T>(val: T) -> impl Sized {
27+
| ^^^^^^^^^^
28+
29+
error: aborting due to 3 previous errors
30+
31+
For more information about this error, try `rustc --explain E0792`.

0 commit comments

Comments
 (0)