Skip to content

region inference sometimes fails to recognize implied bound in closure  #42508

Open
@nikomatsakis

Description

@nikomatsakis

Following a bug sample from @jdm, I encountered this bug. The compiler errors out in this code:

struct Parser<'i: 't, 't> {
  data: &'t mut Vec<&'i String>
}

fn callback1<'i, 't, F>(parser: &mut Parser<'i, 't>, f: F)
    where F: for<'tt1> FnMut(&mut Parser<'i, 'tt1>)
{
    panic!()
}

fn callback2<'i, 't, F>(parser: &mut Parser<'i, 't>, mut f: F)
    where F: for<'tt2> FnMut(&mut Parser<'i, 'tt2>)
{
    callback1(parser, |input| {
        f(input)
    });
}

fn main() {
}

specifically it reports a "cannot infer" lifetime error, complaining about how the lifetime 'tt2 in the call f(input) must be some lifetime 'x where 'i: 'x and 'x: 'tt1 (where 'tt1 is the lifetime that appears in the type of input in the closure). The compiler is upset because it does not know that 'i: 'tt1. Those constraints are correct, but in fact the compiler should be able to deduce that 'i: 'tt1 based on the type of input, which is is &mut Parser<'i, 'tt1>. The implied bounds for this type suggest that 'i: 'tt1. But we fail to see it.

The problem is an interaction with inference. When we call callback1() here, we do not specify the lifetime, and so we create a variable 'x -- that is, the actual type of input is &mut Parser<'x, 'tt2>, where 'x is the inference variable. We then recognize that this means 'x: 'tt2, and we add a "given", which is this hacky bit of code in region inference. Then we infer that 'x must be 'i. But when we go to check that 'x: 'tt2, we substitute 'x to 'i, and then report an error, because we never added anything that tells us that 'i: 'tt2. If you specify callback::<'i> manually, it will work fine.

The most straightforward fix is to use the given logic here too. The better fix is to retool this part of region inference to be more robust, which I am in the process of trying to plan out right now for other reasons anyhow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-inferenceArea: Type inferenceC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions