Type inference fails to determine closure argument type

f9574d7
Opened by Edward Wang at 2024-12-06 13:52:58

The following fails to compile:

pub fn main() {
  let mut xs = HashMap::<(u32, u32), u32>::new();
  let new_el = |&_| 30;  // error: the type of this value must be known in this context

  xs.insert((1,1), 10);
  xs.insert((2,2), 20);
  xs.find_or_insert_with((3,3), new_el);

  println!("{}", xs);
}

The argument type must be explicitly spelled out:

let new_el = |_: &(u32, u32)| 30;

Should the type inference work here?

  1. What happens of you write the definition of new_el inline at the point-of-use?

    Huon Wilson at 2014-03-04 10:11:12

  2. If writing inline at the point of use, it works:

    xs.find_or_insert_with((3,3), |_| 30);
    

    Edward Wang at 2014-03-04 15:03:49

  3. This API is gone now, and I am bad with the new Entry API. @Gankro ?

    Steve Klabnik at 2015-01-23 03:19:42

  4. use std::collections::HashMap;
    
    pub fn main() {
      let mut xs = HashMap::<(u32, u32), u32>::new();
      let new_el = |v| v.insert(30);  // error: the type of this value must be known in this context
    
      xs.insert((1,1), 10);
      xs.insert((2,2), 20);
      xs.entry((3,3)).get().unwrap_or_else(new_el);
    
      println!("{}", xs);
    }
    
    <anon>:5:20: 5:32 error: the type of this value must be known in this context
    <anon>:5   let new_el = |v| v.insert(30);  // error: the type of this value must be known in this context
                                ^~~~~~~~~~~~
    <anon>:5:16: 5:32 error: can't infer the "kind" of the closure, explicitly annotate it. e.g. `|&:| {}`
    <anon>:5   let new_el = |v| v.insert(30);  // error: the type of this value must be known in this context
                            ^~~~~~~~~~~~~~~~
    <anon>:11:18: 11:20 error: the trait `core::fmt::String` is not implemented for the type `std::collections::hash::map::HashMap<(u32, u32), u32>`
    <anon>:11   println!("{}", xs);
                               ^~
    note: in expansion of format_args!
    <std macros>:2:42: 2:75 note: expansion site
    <std macros>:1:1: 2:77 note: in expansion of println!
    <anon>:11:3: 11:22 note: expansion site
    error: aborting due to 3 previous errors
    playpen: application terminated with error code 101
    Program ended.
    

    Seems to basically do the same thing.

    Aria Desires at 2015-01-23 03:43:33

  5. Another related testcase:

    #![feature(std_misc)]
    use std::collections::HashMap;
    use std::collections::hash_map::VacantEntry;
    pub fn main() {
      let mut xs = HashMap::<(u32, u32), u32>::new();
      let new_el = |v:VacantEntry<(u32, u32),u32>| v.insert(30);
      xs.insert((1,1), 10);
      xs.insert((2,2), 20);
      xs.entry((3,3)).get().unwrap_or_else(new_el);
      println!("{:?}", xs);
    }
    

    gives error: cannot infer an appropriate lifetime for lifetime parameter 'a due to conflicting requirements

    eefriedman at 2015-06-16 03:32:54

  6. Have another related/simplified test case:

    (|x| x.count())(0u8..5)
    

    fails to resolve, while the following works:

    (|x: ::std::ops::Range<_>| x.count())(0u8..5)
    

    arcnmx at 2015-08-06 16:36:35

  7. Triage: this issue is kind of a general one, with lots of cases. I'm not sure how much of this is intended to get resolved, and how much of this is scatted across other issues on the tracker.

    Steve Klabnik at 2017-02-07 20:05:22

  8. https://github.com/rust-lang/rust/issues/27828 has another instance of this.

    Steve Klabnik at 2017-02-07 20:27:46

  9. Current output:

    error[E0282]: type annotations needed
     --> src/main.rs:4:16
      |
    4 |   let new_el = |&_| 30;  // error: the type of this value must be known in this context
      |       ------   ^^^^^^^ cannot infer type for `[closure@src/main.rs:4:16: 4:23]`
      |       |
      |       consider giving `new_el` a type
    

    Edit: current output:

    error[E0282]: type annotations needed for the closure `fn(&_) -> i32`
     --> src/main.rs:4:16
      |
    4 |   let new_el = |&_| 30;  // error: the type of this value must be known in this context
      |                ^^^^^^^ cannot infer type for `[closure@src/main.rs:4:16: 4:23]`
      |
    help: give this closure an explicit return type without `_` placeholders
      |
    4 |   let new_el = |&_| -> i32 { 30 };  // error: the type of this value must be known in this context
      |                     ^^^^^^^^    ^
    

    Esteban Kuber at 2018-08-10 21:15:26

  10. Current output with the rust book example, cannot inference the simple type!

    example from the rust book

    let example_closure = |x| x;
    

    output

    swei@macbook:~/code/examples/workday/src
    $ rustc --version
    rustc 1.41.0-nightly (412f43ac5 2019-11-24)
    
    swei@macbook:~/code/examples/workday/src
    $ cargo build
       Compiling workday v0.1.0 (/Users/swei/code/examples/workday)
    error[E0282]: type annotations needed
     --> src/main.rs:6:28
      |
    6 |     let example_closure = |x| x;
      |                            ^ consider giving this closure parameter a type
    
    

    Alex Wei at 2019-11-27 11:06:34

  11. Amazingly, the rust compiler can inference the type when you use it ...

    fn main() {
        let f = |x| x;
        println!("using it: {}", f(100));
    }
    

    Alex Wei at 2019-11-28 02:37:25

  12. @weisunding what type would you expect |x| x yo be without any further context?

    Esteban Kuber at 2019-12-11 22:50:43

  13. It's the last day of 2021, and I still met a similar problem. The following code snippet works:

    fn set_callback<F>(_: F)
    where
        F: FnOnce(&mut [u8])
    { }
    
    fn foo() {
        set_callback(|_| ());
    }
    

    But the following does not:

    fn set_callback<F>(_: Option<F>)
    where
        F: FnOnce(&mut [u8])
    { }
    
    fn foo() {
        set_callback(Some(|_| ()));
    }
    

    Sirui Mu at 2021-12-31 06:08:43

  14. Current output for the last example:

    error[E0308]: mismatched types
     --> f71.rs:7:5
      |
    7 |     set_callback(Some(|_| ()));
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
      |
      = note: expected trait `for<'a> FnOnce<(&'a mut [u8],)>`
                 found trait `FnOnce<(&mut [u8],)>`
    note: this closure does not fulfill the lifetime requirements
     --> f71.rs:7:23
      |
    7 |     set_callback(Some(|_| ()));
      |                       ^^^
    note: the lifetime requirement is introduced here
     --> f71.rs:3:8
      |
    3 |     F: FnOnce(&mut [u8])
      |        ^^^^^^^^^^^^^^^^^
    help: consider specifying the type of the closure parameters
      |
    7 |     set_callback(Some(|_: &_| ()));
      |                       ~~~~~~~
    
    error: implementation of `FnOnce` is not general enough
     --> f71.rs:7:5
      |
    7 |     set_callback(Some(|_| ()));
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
      |
      = note: closure with signature `fn(&'2 mut [u8])` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`...
      = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2`
    

    Esteban Kuber at 2023-08-14 13:39:53