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

async fn lifetime elision tests #63383

Merged
merged 5 commits into from
Aug 14, 2019
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
37 changes: 37 additions & 0 deletions src/test/ui/self/arbitrary_self_types_pin_lifetime-async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// check-pass
// edition:2018

#![feature(async_await)]

use std::pin::Pin;
use std::task::{Context, Poll};

struct Foo;

impl Foo {
async fn pin_ref(self: Pin<&Self>) -> Pin<&Self> { self }

async fn pin_mut(self: Pin<&mut Self>) -> Pin<&mut Self> { self }

async fn pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> Pin<Pin<Pin<&Self>>> { self }

async fn pin_ref_impl_trait(self: Pin<&Self>) -> impl Clone + '_ { self }

fn b(self: Pin<&Foo>, f: &Foo) -> Pin<&Foo> { self }
}

type Alias<T> = Pin<T>;
impl Foo {
async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> Alias<&Self> { self }
}

// FIXME(Centril): extend with the rest of the non-`async fn` test
// when we allow `async fn`s inside traits and trait implementations.

fn main() {
let mut foo = Foo;
{ Pin::new(&foo).pin_ref() };
{ Pin::new(&mut foo).pin_mut() };
{ Pin::new(Pin::new(Pin::new(&foo))).pin_pin_pin_ref() };
{ Pin::new(&foo).pin_ref_impl_trait() };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: lifetime may not live long enough
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:10:48
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
| - ^^^^^^^^ returning this value requires that `'_` must outlive `'static`
| |
| lifetime `'_` defined here
help: to allow this `impl Trait` to capture borrowed data with lifetime `'_`, add `'_` as a constraint
|
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// edition:2018

#![feature(async_await)]

use std::pin::Pin;

struct Foo;

impl Foo {
async fn f(self: Pin<&Self>) -> impl Clone { self }
//~^ ERROR cannot infer an appropriate lifetime
}

fn main() {
{ Pin::new(&Foo).f() };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: cannot infer an appropriate lifetime
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:10:16
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
| ^^^^ ---------- this return type evaluates to the `'static` lifetime...
| |
| ...but this borrow...
|
note: ...can't outlive the lifetime '_ as defined on the method body at 10:26
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:10:26
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
| ^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime '_ as defined on the method body at 10:26
|
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:10:45
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| ^
|
= note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.

error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:60
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^
|
= note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.

error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:67
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^
|
= note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0106`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// edition:2018

#![feature(async_await)]

use std::pin::Pin;

struct Foo;

impl Foo {
async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
//~^ ERROR missing lifetime specifier
//~| ERROR cannot infer an appropriate lifetime
// FIXME: should be E0623?

async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
//~^ ERROR missing lifetime specifier
//~| ERROR cannot infer an appropriate lifetime
//~| ERROR missing lifetime specifier
//~| ERROR cannot infer an appropriate lifetime
// FIXME: should be E0623?
}

type Alias<T> = Pin<T>;
impl Foo {
async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:10:45
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| ^
|
= note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.

error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:60
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^
|
= note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.

error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:67
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^
|
= note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.

error: cannot infer an appropriate lifetime
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:10:33
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| ^ ---- this return type evaluates to the `'static` lifetime...
| |
| ...but this borrow...
|
note: ...can't outlive the lifetime '_ as defined on the method body at 10:26
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:10:26
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| ^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime '_ as defined on the method body at 10:26
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo + '_ { f }
| ^^^^^^^^^

error: cannot infer an appropriate lifetime
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:16
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^^^^ ...but this borrow... ----------------- this return type evaluates to the `'static` lifetime...
|
note: ...can't outlive the lifetime '_ as defined on the method body at 15:26
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:26
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime '_ as defined on the method body at 15:26
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) + '_ { (self, f) }
| ^^^^^^^^^^^^^^^^^^^^^^

error: cannot infer an appropriate lifetime
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:34
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^ ----------------- this return type evaluates to the `'static` lifetime...
| |
| ...but this borrow...
|
note: ...can't outlive the lifetime '_ as defined on the method body at 15:26
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:26
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| ^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime '_ as defined on the method body at 15:26
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) + '_ { (self, f) }
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0623]: lifetime mismatch
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:25:58
|
LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
| ----- ^^^
| | |
| | ...but data from `arg` is returned here
| this parameter and the return type are declared with different lifetimes...

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0106`.
31 changes: 31 additions & 0 deletions src/test/ui/self/elision/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,34 @@ In each case, we test the following patterns:
- `self: Box<Pin<XXX>>`

In the non-reference cases, `Pin` causes errors so we substitute `Rc`.

### `async fn`

For each of the tests above we also check that `async fn` behaves as an `fn` would.
These tests are in files named `*-async.rs`.

Legends:
- ✓ ⟹ Yes / Pass
- X ⟹ No
- α ⟹ lifetime mismatch
- β ⟹ cannot infer an appropriate lifetime
- γ ⟹ missing lifetime specifier

| `async` file | Pass? | Conforms to `fn`? | How does it diverge? <br/> `fn``async fn` |
| --- | --- | --- | --- |
| `self-async.rs` ||| N/A |
| `struct-async.rs`||| N/A |
| `alias-async.rs`||| N/A |
| `assoc-async.rs`||| N/A |
| `ref-self-async.rs` | X | X | α ⟶ β + γ |
Copy link
Contributor Author

@Centril Centril Aug 8, 2019

Choose a reason for hiding this comment

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

N.B. these cases where things diverge.


While writing these tests I also hit:

#![feature(async_await)]

#![feature(nll)]
// Without it you also get //~^ ERROR cannot infer an appropriate lifetime

struct A;

impl A {
    async fn foo(&self, f: &u32) -> &A {
        self
    }
}

which passes if you remove async but with it you get:

error[E0106]: missing lifetime specifier
 --> src/lib.rs:7:37
  |
7 |     async fn foo(&self, f: &u32) -> &A {
  |                                     ^
  |
  = note: return-position elided lifetimes require exactly one input-position elided lifetime, found multiple.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this seems like a bug, but I see you filed one already (#63388)

| `ref-mut-self-async.rs` | X | X | α ⟶ β + γ |
| `ref-struct-async.rs` | X | X | α ⟶ β + γ |
| `ref-mut-struct-async.rs` | X | X | α ⟶ β + γ |
| `ref-alias-async.rs` | X | X | ✓ ⟶ β + γ |
| `ref-assoc-async.rs` | X | X | ✓ ⟶ β + γ |
| `ref-mut-alias-async.rs` | X | X | ✓ ⟶ β + γ |
| `lt-self-async.rs` | ✓ | ✓ | N/A
| `lt-struct-async.rs` | ✓ | ✓ | N/A
| `lt-alias-async.rs` | ✓ | ✓ | N/A
| `lt-assoc-async.rs` | ✓ | ✓ | N/A
| `lt-ref-self-async.rs` | X | X | α ⟶ β + γ
39 changes: 39 additions & 0 deletions src/test/ui/self/elision/alias-async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// check-pass
// edition:2018

#![feature(async_await)]

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;

struct Struct { }

type Alias = Struct;

impl Struct {
// Test using an alias for `Struct`:

async fn alias(self: Alias, f: &u32) -> &u32 {
f
}

async fn box_Alias(self: Box<Alias>, f: &u32) -> &u32 {
f
}

async fn rc_Alias(self: Rc<Alias>, f: &u32) -> &u32 {
f
}

async fn box_box_Alias(self: Box<Box<Alias>>, f: &u32) -> &u32 {
f
}

async fn box_rc_Alias(self: Box<Rc<Alias>>, f: &u32) -> &u32 {
f
}
}

fn main() { }
43 changes: 43 additions & 0 deletions src/test/ui/self/elision/assoc-async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// check-pass
// edition:2018

#![feature(async_await)]

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;

trait Trait {
type AssocType;
}

struct Struct { }

impl Trait for Struct {
type AssocType = Self;
}

impl Struct {
async fn assoc(self: <Struct as Trait>::AssocType, f: &u32) -> &u32 {
f
}

async fn box_AssocType(self: Box<<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
f
}

async fn rc_AssocType(self: Rc<<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
f
}

async fn box_box_AssocType(self: Box<Box<<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
f
}

async fn box_rc_AssocType(self: Box<Rc<<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
f
}
}

fn main() { }
41 changes: 41 additions & 0 deletions src/test/ui/self/elision/lt-alias-async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// check-pass
// edition:2018

#![feature(async_await)]

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

use std::rc::Rc;

struct Struct<'a> { x: &'a u32 }

type Alias<'a> = Struct<'a>;

impl<'a> Alias<'a> {
async fn take_self(self, f: &u32) -> &u32 {
f
}

async fn take_Alias(self: Alias<'a>, f: &u32) -> &u32 {
f
}

async fn take_Box_Alias(self: Box<Alias<'a>>, f: &u32) -> &u32 {
f
}

async fn take_Box_Box_Alias(self: Box<Box<Alias<'a>>>, f: &u32) -> &u32 {
f
}

async fn take_Rc_Alias(self: Rc<Alias<'a>>, f: &u32) -> &u32 {
f
}

async fn take_Box_Rc_Alias(self: Box<Rc<Alias<'a>>>, f: &u32) -> &u32 {
f
}
}

fn main() { }
Loading