use implied bounds when checking opaque types

This commit is contained in:
Ali MJ Al-Nasrawy 2022-12-22 14:36:09 +03:00
parent 4a18324a4d
commit d548747c85
7 changed files with 189 additions and 4 deletions

View file

@ -0,0 +1,25 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/wf-in-associated-type.rs:36:23
|
LL | type Opaque = impl Sized + 'a;
| ^^^^^^^^^^^^^^^ ...so that the type `&'a T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | impl<'a, T: 'a> Trait<'a, T> for () {
| ++++
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/wf-in-associated-type.rs:36:23
|
LL | type Opaque = impl Sized + 'a;
| ^^^^^^^^^^^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
|
help: consider adding an explicit lifetime bound...
|
LL | impl<'a, T: 'a> Trait<'a, T> for () {
| ++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0309`.

View file

@ -0,0 +1,45 @@
// WF check for impl Trait in associated type position.
//
// revisions: pass fail
// [pass] check-pass
// [fail] check-fail
#![feature(impl_trait_in_assoc_type)]
// The hidden type here (`&'a T`) requires proving `T: 'a`.
// We know it holds because of implied bounds from the impl header.
#[cfg(pass)]
mod pass {
trait Trait<Req> {
type Opaque1;
fn constrain_opaque1(req: Req) -> Self::Opaque1;
}
impl<'a, T> Trait<&'a T> for () {
type Opaque1 = impl IntoIterator<Item = impl Sized + 'a>;
fn constrain_opaque1(req: &'a T) -> Self::Opaque1 {
[req]
}
}
}
// The hidden type here (`&'a T`) requires proving `T: 'a`,
// but that is not known to hold in the impl.
#[cfg(fail)]
mod fail {
trait Trait<'a, T> {
type Opaque;
fn constrain_opaque(req: &'a T) -> Self::Opaque;
}
impl<'a, T> Trait<'a, T> for () {
type Opaque = impl Sized + 'a;
//[fail]~^ ERROR the parameter type `T` may not live long enough
//[fail]~| ERROR the parameter type `T` may not live long enough
fn constrain_opaque(req: &'a T) -> Self::Opaque {
req
}
}
}
fn main() {}

View file

@ -0,0 +1,19 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:55:27
|
LL | type InnerOpaque<T> = impl Sized;
| ^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
note: ...that is required by this bound
--> $DIR/wf-nested.rs:12:20
|
LL | struct IsStatic<T: 'static>(T);
| ^^^^^^^
help: consider adding an explicit lifetime bound...
|
LL | type InnerOpaque<T: 'static> = impl Sized;
| +++++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.

View file

@ -0,0 +1,14 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:46:17
|
LL | let _ = outer.get();
| ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | fn test<T: 'static>() {
| +++++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.

View file

@ -0,0 +1,60 @@
// Well-formedness of nested opaque types, i.e. `impl Sized` in
// `type Outer = impl Trait<Assoc = impl Sized>`.
// See the comments below.
//
// revisions: pass pass_sound fail
// [pass] check-pass
// [pass_sound] check-fail
// [fail] check-fail
#![feature(type_alias_impl_trait)]
struct IsStatic<T: 'static>(T);
trait Trait<In> {
type Out;
fn get(&self) -> Result<Self::Out, ()> {
Err(())
}
}
impl<T> Trait<&'static T> for () {
type Out = IsStatic<T>;
}
// The hidden type for `impl Sized` is `IsStatic<T>`, which requires `T: 'static`.
// We know it is well-formed because it can *only* be referenced as a projection:
// <OuterOpaque<T> as Trait<&'static T>>::Out`.
// So any instantiation of the type already requires proving `T: 'static`.
#[cfg(pass)]
mod pass {
use super::*;
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
fn define<T>() -> OuterOpaque<T> {}
}
// Test the soundness of `pass` - We should require `T: 'static` at the use site.
#[cfg(pass_sound)]
mod pass_sound {
use super::*;
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
fn define<T>() -> OuterOpaque<T> {}
fn test<T>() {
let outer = define::<T>();
let _ = outer.get(); //[pass_sound]~ ERROR `T` may not live long enough
}
}
// Similar to `pass` but here `impl Sized` can be referenced directly as
// InnerOpaque<T>, so we require an explicit bound `T: 'static`.
#[cfg(fail)]
mod fail {
use super::*;
type InnerOpaque<T> = impl Sized; //[fail]~ ERROR `T` may not live long enough
type OuterOpaque<T> = impl Trait<&'static T, Out = InnerOpaque<T>>;
fn define<T>() -> OuterOpaque<T> {}
}
fn main() {}