mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 14:01:51 +00:00
check for non-defining uses of RPIT
This commit is contained in:
parent
3071e0aef6
commit
95fddbc501
@ -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(_)),
|
||||||
};
|
};
|
||||||
|
@ -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 {
|
||||||
|
@ -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`.
|
||||||
|
@ -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`
|
||||||
}
|
}
|
||||||
|
@ -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`.
|
||||||
|
19
tests/ui/impl-trait/rpit/equal-lifetime-params-ok.rs
Normal file
19
tests/ui/impl-trait/rpit/equal-lifetime-params-ok.rs
Normal 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() {}
|
14
tests/ui/impl-trait/rpit/non-defining-use.rs
Normal file
14
tests/ui/impl-trait/rpit/non-defining-use.rs
Normal 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() {}
|
31
tests/ui/impl-trait/rpit/non-defining-use.stderr
Normal file
31
tests/ui/impl-trait/rpit/non-defining-use.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user