Skip to content

async/await: Potentially incorrect lifetime handling when structs with lifetimes are referenced #58884

@Matthias247

Description

@Matthias247

The following code (playground) produces a compiler error, even if there doesn't seem to be an obvious lifetime issue:

#![feature(futures_api, async_await, await_macro)]

struct Ctx<'a> {
    a: &'a str,
}

async fn read_loop<'a>(
    ctx: &'a mut Ctx<'a>,
) -> Result<(), ()>
{
    loop {
        await!(read_single(ctx))?;
    }
    Ok(())
}

async fn read_single<'a>(
    ctx: &'a mut Ctx<'a>,
) -> Result<(), ()>
{
    let _ = ctx.a;
    Ok(())
}

The error message is:

error[E0499]: cannot borrow `*ctx` as mutable more than once at a time
  --> src/lib.rs:12:28
   |
8  |     ctx: &'a mut Ctx<'a>,
   |     --- lifetime `'1` appears in the type of `ctx`
...
12 |         await!(read_single(ctx))?;
   |                ------------^^^-
   |                |           |
   |                |           mutable borrow starts here in previous iteration of loop
   |                argument requires that `*ctx` is borrowed for `'1`

That seems very confusing (or wrong), given that the function doesn't return anything with a lifetime. It works without the loop. An additional scope doesn't help.

I tried to work around it by introducing another lifetime for ctx, but doesn't work, since async/await doesn't support it yet.

I got another hint to write an explicit impl Future signature, which allows compiling this simplified example: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=f006c176dea64435e984cb46bcfef56d
But I feel the more basic variant should work too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions