Skip to content

type annotation of closure args breaks borrow checking #100002

Open
@aliemjay

Description

@aliemjay

This example compiles as expected:

fn main() {
    let mut list = vec![];
    let mut add_to_list = |name: _| {
        list.push(name);
    };
    
    let name = String::from("name1");
    add_to_list(&name);
}

but when a type annotation is added to the closure argument, it fails:

-    let mut add_to_list = |name: _| {
+    let mut add_to_list = |name: &str| {

Workaround

Sometimes type annotation is necessary when type inference fails. :

fn main() {
    let mut list = vec![];
    let mut add_to_list = |name: _| { //ERROR type annotations needed
        if !name.is_empty() {
            list.push(name);
        }
    };
    
    let name = String::from("name1");
    add_to_list(&name);
}

In this case you can use this ugly hack to annotate the type in the closure body:

     let mut add_to_list = |name: _| {
+        let name: &str = name; // hack: annotate the type here to avoid rustc bug #xxx
         if !name.is_empty() {

But why?

When rustc encounters such closure, It has to pick up one of these two types for the closure:

/// A closure that expects an argument of SOME specific lifetime, `'a`.
type FnSig1<'a> = dyn         FnMut(&'a str);

/// A closure that expects an argument of ANY lifetime.
/// Aka higher-ranked lifetime.
type FnSig2     = dyn for<'a> FnMut(&'a str);

We want the first one here but the compiler is not smart enough to infer this. Instead it follows a set of dumb rules1 that leads it to the second type, and then it fails when borrow-checking the closure for the same reason the following fails:

fn test<'a, 'b>(mut list: Vec<&'a str>, name: &'b str) {
    list.push(name);
}

There is a promising work on a-mir-fomality to make this inference smarter.

Footnotes

  1. simply if the lifetime appears in type annotation, it's inferred to be higher-ranked

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.T-typesRelevant to the types 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