Skip to content

Strange borrowing issue in inherent async method. #68950

Closed

Description

@crlf0710

Not sure whether it's a bug, but it is indeed strange...

struct A;
// this compiles
fn test(s: &mut A, arg: &str, handler: Box<dyn Fn() + 'static>) {
        
}
// this doesn't
impl A {
    async fn test2(&mut self, arg: &str, handler: Box<dyn Fn() + 'static>) {
        
    }
}

test2 errors with:

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
  --> src/lib.rs:8:76
   |
8  |     async fn test2(&mut self, arg: &str, handler: Box<dyn Fn() + 'static>) {
   |                                                                            ^
   |

Activity

  1. crlf0710 commented on Feb 8, 2020

    @crlf0710
    MemberAuthor

    @rustbot modify labels to +A-async-await +C-bug +T-compiler

  2. added
    C-bugCategory: This is a bug.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Feb 8, 2020
  3. crlf0710 commented on Feb 8, 2020

    @crlf0710
    MemberAuthor

    Seems similar to #68759 ....

  4. Aaron1011 commented on Feb 11, 2020

    @Aaron1011
    Contributor

    This appears to have the same underlying cause as #64552 (which @csmoe is working on in #68362).

    When you write handler: Box<dyn FnOnce() + 'static> (or handler: Box<dyn FnOnce()>, which desugars to the same thing), the AST lowering doesn't create a lifetime parameter in the created opaque type, since you don't need a lifetime parameter for 'static. However,

    However, when we create the generator type, we forget that the region is 'static:

    // The types in the generator interior contain lifetimes local to the generator itself,
    // which should not be exposed outside of the generator. Therefore, we replace these
    // lifetimes with existentially-bound lifetimes, which reflect the exact value of the
    // lifetimes not being known by users.
    //
    // These lifetimes are used in auto trait impl checking (for example,
    // if a Sync generator contains an &'α T, we need to check whether &'α T: Sync),
    // so knowledge of the exact relationships between them isn't particularly important.
    debug!("types in generator {:?}, span = {:?}", type_list, body.value.span);
    // Replace all regions inside the generator interior with late bound regions
    // Note that each region slot in the types gets a new fresh late bound region,
    // which means that none of the regions inside relate to any other, even if
    // typeck had previously found constraints that would cause them to be related.
    let mut counter = 0;
    let type_list = fcx.tcx.fold_regions(&type_list, &mut false, |_, current_depth| {
    counter += 1;
    fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter)))
    });

    Thus, we end up trying to process a member constraint for some newly created region _#0r. Since by construction we have no constraints for it, we cannot prove that it is equal to any of the regions in the member constraint (even though it's "really" 'static).

    As a workaround, we could special-case 'static during the creation of the generator type, and leave it as-is instead of creating a fresh late-bound region.

    As in #64552, I believe the full solution is for generator types to carry 'extra' region constraints with them in some form, so that we don't lose the lexical region information that we had prior to the lowering.

  5. tmandry commented on Mar 3, 2020

    @tmandry
    Member

    Thanks @Aaron1011. I'm going to close this as a duplicate of #64552, but note on the issue that we should add a test with the code from this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions