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

type alias impl trait: add tests showing that hidden type only outlives lifetimes that occur in bounds #103876

Merged
merged 1 commit into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1705,29 +1705,29 @@ impl<'tcx> RegionInferenceContext<'tcx> {
});
}

#[instrument(level = "debug", skip(self, infcx, errors_buffer))]
fn check_member_constraints(
&self,
infcx: &InferCtxt<'tcx>,
errors_buffer: &mut RegionErrors<'tcx>,
) {
let member_constraints = self.member_constraints.clone();
for m_c_i in member_constraints.all_indices() {
debug!("check_member_constraint(m_c_i={:?})", m_c_i);
debug!(?m_c_i);
let m_c = &member_constraints[m_c_i];
let member_region_vid = m_c.member_region_vid;
debug!(
"check_member_constraint: member_region_vid={:?} with value {}",
member_region_vid,
self.region_value_str(member_region_vid),
?member_region_vid,
value = ?self.region_value_str(member_region_vid),
);
let choice_regions = member_constraints.choice_regions(m_c_i);
debug!("check_member_constraint: choice_regions={:?}", choice_regions);
debug!(?choice_regions);

// Did the member region wind up equal to any of the option regions?
if let Some(o) =
choice_regions.iter().find(|&&o_r| self.eval_equal(o_r, m_c.member_region_vid))
{
debug!("check_member_constraint: evaluated as equal to {:?}", o);
debug!("evaluated as equal to {:?}", o);
continue;
}

Expand Down
25 changes: 25 additions & 0 deletions src/test/ui/type-alias-impl-trait/imply_bounds_from_bounds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// check-pass

#![feature(type_alias_impl_trait)]

trait Callable {
type Output;
fn call() -> Self::Output;
}

impl<'a> Callable for &'a () {
type Output = impl Sized;
fn call() -> Self::Output {}
}

fn test<'a>() -> impl Sized {
<&'a () as Callable>::call()
}

fn want_static<T: 'static>(_: T) {}

fn test2<'a>() {
want_static(<&'a () as Callable>::call());
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#![feature(type_alias_impl_trait)]

trait Callable {
type Output;
fn call(x: Self) -> Self::Output;
}

trait PlusOne {
fn plus_one(&mut self);
}

impl<'a> PlusOne for &'a mut i32 {
fn plus_one(&mut self) {
**self += 1;
}
}

impl<T: PlusOne> Callable for T {
type Output = impl PlusOne;
fn call(t: T) -> Self::Output { t }
}

fn test<'a>(y: &'a mut i32) -> impl PlusOne {
<&'a mut i32 as Callable>::call(y)
//~^ ERROR hidden type for `impl PlusOne` captures lifetime that does not appear in bounds
}

fn main() {
let mut z = 42;
let mut thing = test(&mut z);
let mut thing2 = test(&mut z);
thing.plus_one();
assert_eq!(z, 43);
thing2.plus_one();
assert_eq!(z, 44);
thing.plus_one();
assert_eq!(z, 45);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0700]: hidden type for `impl PlusOne` captures lifetime that does not appear in bounds
--> $DIR/imply_bounds_from_bounds_param.rs:24:5
|
LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne {
| -- hidden type `<&'a mut i32 as Callable>::Output` captures the lifetime `'a` as defined here
LL | <&'a mut i32 as Callable>::call(y)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that `impl PlusOne` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne + 'a {
| ++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0700`.
38 changes: 38 additions & 0 deletions src/test/ui/type-alias-impl-trait/self_implication.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// check-pass

#![feature(type_alias_impl_trait)]
fn foo() {
struct Foo<'a> {
x: &'a mut u8,
}
impl<'a> Foo<'a> {
fn foo(&self) -> impl Sized {}
}
// use site
let mut x = 5;
let y = Foo { x: &mut x };
let z = y.foo();
let _a = &x; // invalidate the `&'a mut`in `y`
let _b = z; // this should *not* check that `'a` in the type `Foo<'a>::foo::opaque` is live
}

fn bar() {
struct Foo<'a> {
x: &'a mut u8,
}

// desugared
type FooX<'a> = impl Sized;
impl<'a> Foo<'a> {
fn foo(&self) -> FooX<'a> {}
}

// use site
let mut x = 5;
let y = Foo { x: &mut x };
let z = y.foo();
let _a = &x; // invalidate the `&'a mut`in `y`
let _b = z; // this should *not* check that `'a` in the type `Foo<'a>::foo::opaque` is live
Copy link
Contributor

@lcnr lcnr Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that comment seems wrong? If you have FooX<'a> with an explicit 'a the error feels correct? 🤔

can you add a comment to the top of the file explaining what we're testing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that comment seems wrong? If you have FooX<'a> with an explicit 'a the error feels correct?

that's the thing... lifetimes on type aliases should not matter for anything. Only lifetimes in the aliased type. Once/if we avoid adding uncaptured lifetimes to opaque types, this would automatically end up compiling. It may end up working with #103491 or with that plus some small changes.

}

fn main() {}